RemoteDrawingEngine: Reduce RP_READ_BITMAP result timeout.
[haiku.git] / src / preferences / locale / LocaleWindow.cpp
blob0eff7167a26f95f37be63e82c86ee16be5824cb6
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 <SeparatorView.h>
26 #include <StringView.h>
27 #include <TabView.h>
28 #include <UnicodeChar.h>
30 #include "FormatSettingsView.h"
31 #include "LocalePreflet.h"
32 #include "LanguageListView.h"
35 using BPrivate::MutableLocaleRoster;
38 #undef B_TRANSLATION_CONTEXT
39 #define B_TRANSLATION_CONTEXT "Locale Preflet Window"
42 static const uint32 kMsgLanguageInvoked = 'LaIv';
43 static const uint32 kMsgLanguageDragged = 'LaDr';
44 static const uint32 kMsgPreferredLanguageInvoked = 'PLIv';
45 static const uint32 kMsgPreferredLanguageDragged = 'PLDr';
46 static const uint32 kMsgPreferredLanguageDeleted = 'PLDl';
47 static const uint32 kMsgConventionsSelection = 'csel';
48 static const uint32 kMsgDefaults = 'dflt';
50 static const uint32 kMsgPreferredLanguagesChanged = 'lang';
51 static const uint32 kMsgFilesystemTranslationChanged = 'fsys';
54 static int
55 compare_typed_list_items(const BListItem* _a, const BListItem* _b)
57 static BCollator collator;
59 LanguageListItem* a = (LanguageListItem*)_a;
60 LanguageListItem* b = (LanguageListItem*)_b;
62 return collator.Compare(a->Text(), b->Text());
66 // #pragma mark -
68 LocaleWindow::LocaleWindow()
70 BWindow(BRect(0, 0, 0, 0), B_TRANSLATE_SYSTEM_NAME("Locale"), B_TITLED_WINDOW,
71 B_QUIT_ON_WINDOW_CLOSE | B_ASYNCHRONOUS_CONTROLS
72 | B_AUTO_UPDATE_SIZE_LIMITS),
73 fInitialConventionsItem(NULL),
74 fDefaultConventionsItem(NULL),
75 fFilesystemTranslationCheckbox(NULL)
77 SetLayout(new BGroupLayout(B_HORIZONTAL));
79 float spacing = be_control_look->DefaultItemSpacing();
81 BTabView* tabView = new BTabView("tabview", B_WIDTH_FROM_WIDEST);
82 tabView->SetBorder(B_NO_BORDER);
84 BGroupView* languageTab = new BGroupView(B_TRANSLATE("Language"),
85 B_HORIZONTAL, spacing);
87 // first list: available languages
88 fLanguageListView = new LanguageListView("available",
89 B_MULTIPLE_SELECTION_LIST);
90 BScrollView* scrollView = new BScrollView("scroller", fLanguageListView,
91 B_WILL_DRAW | B_FRAME_EVENTS, true, true);
93 fLanguageListView->SetInvocationMessage(new BMessage(kMsgLanguageInvoked));
94 fLanguageListView->SetDragMessage(new BMessage(kMsgLanguageDragged));
95 fLanguageListView->SetGlobalDropTargetIndicator(true);
97 BFont font;
98 fLanguageListView->GetFont(&font);
100 // Fill the language list from the LocaleRoster data
101 BMessage availableLanguages;
102 if (BLocaleRoster::Default()->GetAvailableLanguages(&availableLanguages)
103 == B_OK) {
104 BString currentID;
105 LanguageListItem* currentToplevelItem = NULL;
107 for (int i = 0; availableLanguages.FindString("language", i, &currentID)
108 == B_OK; i++) {
109 // Now get the human-readable, native name for each language
110 BString name;
111 BLanguage currentLanguage(currentID.String());
112 currentLanguage.GetNativeName(name);
114 int nameLength = name.CountChars();
115 bool hasGlyphs[nameLength];
116 font.GetHasGlyphs(name.String(), nameLength, hasGlyphs);
117 for (int32 i = 0; i < nameLength; ++i) {
118 if (!hasGlyphs[i]) {
119 // replace by name translated to current language
120 currentLanguage.GetName(name);
121 break;
125 LanguageListItem* item;
126 if (currentLanguage.IsCountrySpecific()) {
127 item = new LanguageListItemWithFlag(name, currentID.String(),
128 currentLanguage.Code(), currentLanguage.CountryCode());
129 } else {
130 item = new LanguageListItem(name, currentID.String(),
131 currentLanguage.Code());
134 if (currentLanguage.IsCountrySpecific()
135 && currentToplevelItem != NULL
136 && currentToplevelItem->Code() == item->Code()) {
137 fLanguageListView->AddUnder(item, currentToplevelItem);
138 } else if (currentLanguage.ScriptCode() != NULL
139 && currentToplevelItem != NULL
140 && currentToplevelItem->Code() == item->Code()) {
141 // This is a script for some language, skip it and add the
142 // country-specific variants to the parent directly
143 delete item;
144 } else {
145 // This is a generic language, add it at top-level
146 fLanguageListView->AddItem(item);
147 item->SetExpanded(false);
148 currentToplevelItem = item;
152 fLanguageListView->FullListSortItems(compare_typed_list_items);
153 } else {
154 BAlert* alert = new BAlert("Error",
155 B_TRANSLATE("Unable to find the available languages! You can't "
156 "use this preflet!"),
157 B_TRANSLATE("OK"), NULL, NULL,
158 B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_STOP_ALERT);
159 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
160 alert->Go();
163 // Second list: active languages
164 fPreferredListView = new LanguageListView("preferred",
165 B_MULTIPLE_SELECTION_LIST);
166 BScrollView* scrollViewEnabled = new BScrollView("scroller",
167 fPreferredListView, B_WILL_DRAW | B_FRAME_EVENTS, true, true);
169 fPreferredListView->SetInvocationMessage(
170 new BMessage(kMsgPreferredLanguageInvoked));
171 fPreferredListView->SetDeleteMessage(
172 new BMessage(kMsgPreferredLanguageDeleted));
173 fPreferredListView->SetDragMessage(
174 new BMessage(kMsgPreferredLanguageDragged));
176 BLayoutBuilder::Group<>(languageTab)
177 .AddGroup(B_VERTICAL)
178 .Add(new BStringView("", B_TRANSLATE("Available languages")))
179 .Add(scrollView)
180 .End()
181 .AddGroup(B_VERTICAL)
182 .Add(new BStringView("", B_TRANSLATE("Preferred languages")))
183 .Add(scrollViewEnabled)
184 .End()
185 .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
186 B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING);
188 BView* countryTab = new BView(B_TRANSLATE("Formatting"), B_WILL_DRAW);
189 countryTab->SetLayout(new BGroupLayout(B_VERTICAL, 0));
191 fConventionsListView = new LanguageListView("formatting",
192 B_SINGLE_SELECTION_LIST);
193 scrollView = new BScrollView("scroller", fConventionsListView,
194 B_WILL_DRAW | B_FRAME_EVENTS, true, true);
195 fConventionsListView->SetSelectionMessage(
196 new BMessage(kMsgConventionsSelection));
198 // get all available formatting conventions (by language)
199 BFormattingConventions initialConventions;
200 BLocale::Default()->GetFormattingConventions(&initialConventions);
201 BString conventionsID;
202 fInitialConventionsItem = NULL;
203 LanguageListItem* currentToplevelItem = NULL;
204 for (int i = 0;
205 availableLanguages.FindString("language", i, &conventionsID) == B_OK;
206 i++) {
207 BFormattingConventions conventions(conventionsID);
208 BString conventionsName;
209 conventions.GetName(conventionsName);
211 LanguageListItem* item;
212 if (conventions.AreCountrySpecific()) {
213 item = new LanguageListItemWithFlag(conventionsName, conventionsID,
214 conventions.LanguageCode(), conventions.CountryCode());
215 } else {
216 item = new LanguageListItem(conventionsName, conventionsID,
217 conventions.LanguageCode());
219 if (!strcmp(conventionsID, "en_US"))
220 fDefaultConventionsItem = item;
221 if (conventions.AreCountrySpecific()
222 && currentToplevelItem != NULL
223 && currentToplevelItem->Code() == item->Code()) {
224 if (!strcmp(conventionsID, initialConventions.ID())) {
225 fConventionsListView->Expand(currentToplevelItem);
226 fInitialConventionsItem = item;
228 fConventionsListView->AddUnder(item, currentToplevelItem);
229 } else {
230 // This conventions-item isn't country-specific, add it at top-level
231 fConventionsListView->AddItem(item);
232 item->SetExpanded(false);
233 currentToplevelItem = item;
234 if (!strcmp(conventionsID, initialConventions.ID()))
235 fInitialConventionsItem = item;
239 fConventionsListView->FullListSortItems(compare_typed_list_items);
240 if (fInitialConventionsItem != NULL) {
241 fConventionsListView->Select(fConventionsListView->IndexOf(
242 fInitialConventionsItem));
245 fConventionsListView->SetExplicitMinSize(BSize(20 * be_plain_font->Size(),
246 B_SIZE_UNSET));
248 fFormatView = new FormatSettingsView();
250 countryTab->AddChild(BLayoutBuilder::Group<>(B_HORIZONTAL, spacing)
251 .AddGroup(B_VERTICAL, 3)
252 .Add(scrollView)
253 .End()
254 .Add(fFormatView)
255 .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
256 B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING));
258 BView* optionsTab = new BView(B_TRANSLATE("Options"), B_WILL_DRAW);
259 optionsTab->SetLayout(new BGroupLayout(B_VERTICAL, 0));
261 fFilesystemTranslationCheckbox = new BCheckBox("filesystemTranslation",
262 B_TRANSLATE("Translate application and folder names in Deskbar and Tracker."),
263 new BMessage(kMsgFilesystemTranslationChanged));
265 fFilesystemTranslationCheckbox->SetValue(
266 BLocaleRoster::Default()->IsFilesystemTranslationPreferred());
268 optionsTab->AddChild(BLayoutBuilder::Group<>(B_VERTICAL)
269 .Add(fFilesystemTranslationCheckbox)
270 .AddGlue()
271 .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
272 B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING));
274 tabView->AddTab(languageTab);
275 tabView->AddTab(countryTab);
276 tabView->AddTab(optionsTab);
278 BButton* button
279 = new BButton(B_TRANSLATE("Defaults"), new BMessage(kMsgDefaults));
281 fRevertButton
282 = new BButton(B_TRANSLATE("Revert"), new BMessage(kMsgRevert));
283 fRevertButton->SetEnabled(false);
285 BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
286 .SetInsets(0, B_USE_DEFAULT_SPACING, 0, B_USE_WINDOW_SPACING)
287 .Add(tabView)
288 .Add(new BSeparatorView(B_HORIZONTAL))
289 .AddGroup(B_HORIZONTAL)
290 .Add(button)
291 .Add(fRevertButton)
292 .SetInsets(B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING,
293 B_USE_WINDOW_SPACING, 0)
294 .AddGlue();
296 _Refresh(true);
297 _SettingsReverted();
298 CenterOnScreen();
302 LocaleWindow::~LocaleWindow()
307 void
308 LocaleWindow::MessageReceived(BMessage* message)
310 switch (message->what) {
311 case B_LOCALE_CHANGED:
312 fFormatView->MessageReceived(message);
313 break;
315 case kMsgDefaults:
316 _Defaults();
317 break;
319 case kMsgRevert:
321 _Revert();
322 fFormatView->Revert();
323 fConventionsListView->DeselectAll();
324 if (fInitialConventionsItem != NULL) {
325 BListItem* superitem
326 = fConventionsListView->Superitem(fInitialConventionsItem);
327 if (superitem != NULL)
328 superitem->SetExpanded(true);
329 fConventionsListView->Select(fConventionsListView->IndexOf(
330 fInitialConventionsItem));
331 fConventionsListView->ScrollToSelection();
333 _SettingsReverted();
334 break;
337 case kMsgSettingsChanged:
338 _SettingsChanged();
339 break;
341 case kMsgLanguageDragged:
343 void* target = NULL;
344 if (message->FindPointer("drop_target", &target) != B_OK
345 || target != fPreferredListView)
346 break;
348 // Add from available languages to preferred languages
349 int32 dropIndex;
350 if (message->FindInt32("drop_index", &dropIndex) != B_OK)
351 dropIndex = fPreferredListView->CountItems();
353 int32 index = 0;
354 for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK;
355 i++) {
356 LanguageListItem* item = static_cast<LanguageListItem*>(
357 fLanguageListView->ItemAt(index));
358 _InsertPreferredLanguage(item, dropIndex++);
360 break;
362 case kMsgLanguageInvoked:
364 int32 index = 0;
365 for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK;
366 i++) {
367 LanguageListItem* item = static_cast<LanguageListItem*>(
368 fLanguageListView->ItemAt(index));
369 _InsertPreferredLanguage(item);
371 break;
374 case kMsgPreferredLanguageDragged:
376 void* target = NULL;
377 if (fPreferredListView->CountItems() == 1
378 || message->FindPointer("drop_target", &target) != B_OK)
379 break;
381 if (target == fPreferredListView) {
382 // change ordering
383 int32 dropIndex = message->FindInt32("drop_index");
384 int32 index = 0;
385 for (int32 i = 0;
386 message->FindInt32("index", i, &index) == B_OK;
387 i++, dropIndex++) {
388 if (dropIndex > index) {
389 dropIndex--;
390 index -= i;
392 BListItem* item = fPreferredListView->RemoveItem(index);
393 fPreferredListView->AddItem(item, dropIndex);
396 _PreferredLanguagesChanged();
397 break;
400 // supposed to fall through - remove item
402 case kMsgPreferredLanguageDeleted:
403 case kMsgPreferredLanguageInvoked:
405 if (fPreferredListView->CountItems() == 1)
406 break;
408 // Remove from preferred languages
409 int32 index = 0;
410 for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK;
411 i++) {
412 delete fPreferredListView->RemoveItem(index - i);
414 if (message->what == kMsgPreferredLanguageDeleted) {
415 int32 count = fPreferredListView->CountItems();
416 fPreferredListView->Select(
417 index < count ? index : count - 1);
421 _PreferredLanguagesChanged();
422 break;
425 case kMsgConventionsSelection:
427 // Country selection changed.
428 // Get the new selected country from the ListView and send it to the
429 // main app event handler.
430 void* listView;
431 if (message->FindPointer("source", &listView) != B_OK)
432 break;
434 BListView* conventionsList = static_cast<BListView*>(listView);
435 if (conventionsList == NULL)
436 break;
438 LanguageListItem* item = static_cast<LanguageListItem*>
439 (conventionsList->ItemAt(conventionsList->CurrentSelection()));
440 if (item == NULL)
441 break;
443 BFormattingConventions conventions(item->ID());
444 MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
445 conventions);
447 _SettingsChanged();
448 fFormatView->Refresh();
449 break;
452 case kMsgFilesystemTranslationChanged:
454 MutableLocaleRoster::Default()->SetFilesystemTranslationPreferred(
455 fFilesystemTranslationCheckbox->Value());
457 BAlert* alert = new BAlert(B_TRANSLATE("Locale"),
458 B_TRANSLATE("Deskbar and Tracker need to be restarted for this "
459 "change to take effect. Would you like to restart them now?"),
460 B_TRANSLATE("Cancel"), B_TRANSLATE("Restart"), NULL,
461 B_WIDTH_FROM_WIDEST, B_IDEA_ALERT);
462 alert->SetShortcut(0, B_ESCAPE);
463 alert->Go(new BInvoker(new BMessage(kMsgRestartTrackerAndDeskbar),
464 NULL, be_app));
465 break;
468 default:
469 BWindow::MessageReceived(message);
470 break;
475 bool
476 LocaleWindow::QuitRequested()
478 return true;
482 void
483 LocaleWindow::Show()
485 BWindow::Show();
487 Lock();
488 if (IsLocked()) {
489 fConventionsListView->ScrollToSelection();
490 Unlock();
495 void
496 LocaleWindow::_SettingsChanged()
498 fRevertButton->SetEnabled(fFormatView->IsReversible() || _IsReversible());
502 void
503 LocaleWindow::_SettingsReverted()
505 fRevertButton->SetEnabled(false);
509 bool
510 LocaleWindow::_IsReversible() const
512 BMessage preferredLanguages;
513 BLocaleRoster::Default()->GetPreferredLanguages(&preferredLanguages);
515 return !preferredLanguages.HasSameData(fInitialPreferredLanguages);
519 void
520 LocaleWindow::_PreferredLanguagesChanged()
522 BMessage preferredLanguages;
523 int index = 0;
524 while (index < fPreferredListView->CountItems()) {
525 LanguageListItem* item = static_cast<LanguageListItem*>(
526 fPreferredListView->ItemAt(index));
527 if (item != NULL)
528 preferredLanguages.AddString("language", item->ID());
529 index++;
531 MutableLocaleRoster::Default()->SetPreferredLanguages(&preferredLanguages);
533 _EnableDisableLanguages();
537 void
538 LocaleWindow::_EnableDisableLanguages()
540 DisableUpdates();
542 for (int32 i = 0; i < fLanguageListView->FullListCountItems(); i++) {
543 LanguageListItem* item = static_cast<LanguageListItem*>(
544 fLanguageListView->FullListItemAt(i));
546 bool enable = fPreferredListView->ItemForLanguageID(item->ID()) == NULL;
547 if (item->IsEnabled() != enable) {
548 item->SetEnabled(enable);
550 int32 visibleIndex = fLanguageListView->IndexOf(item);
551 if (visibleIndex >= 0) {
552 if (!enable)
553 fLanguageListView->Deselect(visibleIndex);
554 fLanguageListView->InvalidateItem(visibleIndex);
559 EnableUpdates();
563 void
564 LocaleWindow::_Refresh(bool setInitial)
566 BMessage preferredLanguages;
567 BLocaleRoster::Default()->GetPreferredLanguages(&preferredLanguages);
568 if (setInitial)
569 fInitialPreferredLanguages = preferredLanguages;
571 _SetPreferredLanguages(preferredLanguages);
575 void
576 LocaleWindow::_Revert()
578 _SetPreferredLanguages(fInitialPreferredLanguages);
582 void
583 LocaleWindow::_SetPreferredLanguages(const BMessage& languages)
585 DisableUpdates();
587 // Delete all existing items
588 for (int32 index = fPreferredListView->CountItems(); index-- > 0; ) {
589 delete fPreferredListView->ItemAt(index);
591 fPreferredListView->MakeEmpty();
593 BString languageID;
594 for (int32 index = 0;
595 languages.FindString("language", index, &languageID) == B_OK; index++) {
596 int32 listIndex;
597 LanguageListItem* item = fLanguageListView->ItemForLanguageID(
598 languageID.String(), &listIndex);
599 if (item != NULL) {
600 // We found the item we were looking for, now copy it to
601 // the other list
602 fPreferredListView->AddItem(new LanguageListItem(*item));
606 _EnableDisableLanguages();
607 EnableUpdates();
611 void
612 LocaleWindow::_InsertPreferredLanguage(LanguageListItem* item, int32 atIndex)
614 if (item == NULL || fPreferredListView->ItemForLanguageID(
615 item->ID().String()) != NULL)
616 return;
618 if (atIndex == -1)
619 atIndex = fPreferredListView->CountItems();
621 BLanguage language(item->Code());
622 LanguageListItem* baseItem
623 = fPreferredListView->ItemForLanguageCode(language.Code(), &atIndex);
625 DisableUpdates();
627 fPreferredListView->AddItem(new LanguageListItem(*item), atIndex);
629 // Replace other languages sharing the same base
630 if (baseItem != NULL) {
631 fPreferredListView->RemoveItem(baseItem);
632 delete baseItem;
635 _PreferredLanguagesChanged();
637 EnableUpdates();
641 void
642 LocaleWindow::_Defaults()
644 BMessage preferredLanguages;
645 preferredLanguages.AddString("language", "en");
646 MutableLocaleRoster::Default()->SetPreferredLanguages(&preferredLanguages);
647 _SetPreferredLanguages(preferredLanguages);
649 BFormattingConventions conventions("en_US");
650 MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
651 conventions);
653 fConventionsListView->DeselectAll();
654 if (fDefaultConventionsItem != NULL) {
655 BListItem* superitem
656 = fConventionsListView->Superitem(fDefaultConventionsItem);
657 if (superitem != NULL && !superitem->IsExpanded())
658 fConventionsListView->Expand(superitem);
659 fConventionsListView->Select(fConventionsListView->IndexOf(
660 fDefaultConventionsItem));
661 fConventionsListView->ScrollToSelection();