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.
8 #include "LocaleWindow.h"
13 #include <Application.h>
17 #include <ControlLook.h>
18 #include <FormattingConventions.h>
19 #include <GroupLayout.h>
20 #include <LayoutBuilder.h>
22 #include <MutableLocaleRoster.h>
24 #include <ScrollView.h>
25 #include <StringView.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';
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());
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);
95 fLanguageListView
->GetFont(&font
);
97 // Fill the language list from the LocaleRoster data
98 BMessage availableLanguages
;
99 if (BLocaleRoster::Default()->GetAvailableLanguages(&availableLanguages
)
102 LanguageListItem
* currentToplevelItem
= NULL
;
104 for (int i
= 0; availableLanguages
.FindString("language", i
, ¤tID
)
106 // Now get the human-readable, native name for each language
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
) {
117 // replace by name translated to current language
118 currentLanguage
.GetName(name
);
123 LanguageListItem
* item
;
124 if (currentLanguage
.IsCountrySpecific()) {
125 item
= new LanguageListItemWithFlag(name
, currentID
.String(),
126 currentLanguage
.Code(), currentLanguage
.CountryCode());
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
);
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
);
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
);
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")))
172 .AddGroup(B_VERTICAL
, spacing
)
173 .Add(new BStringView("", B_TRANSLATE("Preferred languages")))
174 .Add(scrollViewEnabled
)
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
;
195 availableLanguages
.FindString("language", i
, &conventionsID
) == B_OK
;
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());
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
);
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(),
238 fFormatView
= new FormatSettingsView();
240 countryTab
->AddChild(BLayoutBuilder::Group
<>(B_HORIZONTAL
, spacing
)
241 .AddGroup(B_VERTICAL
, 3)
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
)
260 .SetInsets(spacing
, spacing
, spacing
, spacing
));
262 tabView
->AddTab(languageTab
);
263 tabView
->AddTab(countryTab
);
264 tabView
->AddTab(optionsTab
);
267 = new BButton(B_TRANSLATE("Defaults"), new BMessage(kMsgDefaults
));
270 = new BButton(B_TRANSLATE("Revert"), new BMessage(kMsgRevert
));
271 fRevertButton
->SetEnabled(false);
273 BLayoutBuilder::Group
<>(this, B_VERTICAL
, spacing
)
275 .AddGroup(B_HORIZONTAL
, spacing
)
280 .SetInsets(spacing
, spacing
, spacing
, spacing
)
289 LocaleWindow::~LocaleWindow()
295 LocaleWindow::MessageReceived(BMessage
* message
)
297 switch (message
->what
) {
298 case B_LOCALE_CHANGED
:
299 fFormatView
->MessageReceived(message
);
309 fFormatView
->Revert();
310 fConventionsListView
->DeselectAll();
311 if (fInitialConventionsItem
!= NULL
) {
313 = fConventionsListView
->Superitem(fInitialConventionsItem
);
314 if (superitem
!= NULL
)
315 superitem
->SetExpanded(true);
316 fConventionsListView
->Select(fConventionsListView
->IndexOf(
317 fInitialConventionsItem
));
318 fConventionsListView
->ScrollToSelection();
324 case kMsgSettingsChanged
:
328 case kMsgLanguageDragged
:
331 if (message
->FindPointer("drop_target", &target
) != B_OK
332 || target
!= fPreferredListView
)
335 // Add from available languages to preferred languages
337 if (message
->FindInt32("drop_index", &dropIndex
) != B_OK
)
338 dropIndex
= fPreferredListView
->CountItems();
341 for (int32 i
= 0; message
->FindInt32("index", i
, &index
) == B_OK
;
343 LanguageListItem
* item
= static_cast<LanguageListItem
*>(
344 fLanguageListView
->ItemAt(index
));
345 _InsertPreferredLanguage(item
, dropIndex
++);
349 case kMsgLanguageInvoked
:
352 for (int32 i
= 0; message
->FindInt32("index", i
, &index
) == B_OK
;
354 LanguageListItem
* item
= static_cast<LanguageListItem
*>(
355 fLanguageListView
->ItemAt(index
));
356 _InsertPreferredLanguage(item
);
361 case kMsgPreferredLanguageDragged
:
364 if (fPreferredListView
->CountItems() == 1
365 || message
->FindPointer("drop_target", &target
) != B_OK
)
368 if (target
== fPreferredListView
) {
370 int32 dropIndex
= message
->FindInt32("drop_index");
373 message
->FindInt32("index", i
, &index
) == B_OK
;
375 if (dropIndex
> index
) {
379 BListItem
* item
= fPreferredListView
->RemoveItem(index
);
380 fPreferredListView
->AddItem(item
, dropIndex
);
383 _PreferredLanguagesChanged();
387 // supposed to fall through - remove item
389 case kMsgPreferredLanguageDeleted
:
390 case kMsgPreferredLanguageInvoked
:
392 if (fPreferredListView
->CountItems() == 1)
395 // Remove from preferred languages
397 for (int32 i
= 0; message
->FindInt32("index", i
, &index
) == B_OK
;
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();
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.
418 if (message
->FindPointer("source", &listView
) != B_OK
)
421 BListView
* conventionsList
= static_cast<BListView
*>(listView
);
422 if (conventionsList
== NULL
)
425 LanguageListItem
* item
= static_cast<LanguageListItem
*>
426 (conventionsList
->ItemAt(conventionsList
->CurrentSelection()));
430 BFormattingConventions
conventions(item
->ID());
431 MutableLocaleRoster::Default()->SetDefaultFormattingConventions(
435 fFormatView
->Refresh();
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
),
456 BWindow::MessageReceived(message
);
463 LocaleWindow::QuitRequested()
476 fConventionsListView
->ScrollToSelection();
483 LocaleWindow::_SettingsChanged()
485 fRevertButton
->SetEnabled(fFormatView
->IsReversible() || _IsReversible());
490 LocaleWindow::_SettingsReverted()
492 fRevertButton
->SetEnabled(false);
497 LocaleWindow::_IsReversible() const
499 BMessage preferredLanguages
;
500 BLocaleRoster::Default()->GetPreferredLanguages(&preferredLanguages
);
502 return !preferredLanguages
.HasSameData(fInitialPreferredLanguages
);
507 LocaleWindow::_PreferredLanguagesChanged()
509 BMessage preferredLanguages
;
511 while (index
< fPreferredListView
->CountItems()) {
512 LanguageListItem
* item
= static_cast<LanguageListItem
*>(
513 fPreferredListView
->ItemAt(index
));
515 preferredLanguages
.AddString("language", item
->ID());
518 MutableLocaleRoster::Default()->SetPreferredLanguages(&preferredLanguages
);
520 _EnableDisableLanguages();
525 LocaleWindow::_EnableDisableLanguages()
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) {
540 fLanguageListView
->Deselect(visibleIndex
);
541 fLanguageListView
->InvalidateItem(visibleIndex
);
551 LocaleWindow::_Refresh(bool setInitial
)
553 BMessage preferredLanguages
;
554 BLocaleRoster::Default()->GetPreferredLanguages(&preferredLanguages
);
556 fInitialPreferredLanguages
= preferredLanguages
;
558 _SetPreferredLanguages(preferredLanguages
);
563 LocaleWindow::_Revert()
565 _SetPreferredLanguages(fInitialPreferredLanguages
);
570 LocaleWindow::_SetPreferredLanguages(const BMessage
& languages
)
574 // Delete all existing items
575 for (int32 index
= fPreferredListView
->CountItems(); index
-- > 0; ) {
576 delete fPreferredListView
->ItemAt(index
);
578 fPreferredListView
->MakeEmpty();
581 for (int32 index
= 0;
582 languages
.FindString("language", index
, &languageID
) == B_OK
; index
++) {
584 LanguageListItem
* item
= fLanguageListView
->ItemForLanguageID(
585 languageID
.String(), &listIndex
);
587 // We found the item we were looking for, now copy it to
589 fPreferredListView
->AddItem(new LanguageListItem(*item
));
593 _EnableDisableLanguages();
599 LocaleWindow::_InsertPreferredLanguage(LanguageListItem
* item
, int32 atIndex
)
601 if (item
== NULL
|| fPreferredListView
->ItemForLanguageID(
602 item
->ID().String()) != NULL
)
606 atIndex
= fPreferredListView
->CountItems();
608 BLanguage
language(item
->Code());
609 LanguageListItem
* baseItem
610 = fPreferredListView
->ItemForLanguageCode(language
.Code(), &atIndex
);
614 fPreferredListView
->AddItem(new LanguageListItem(*item
), atIndex
);
616 // Replace other languages sharing the same base
617 if (baseItem
!= NULL
) {
618 fPreferredListView
->RemoveItem(baseItem
);
622 _PreferredLanguagesChanged();
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(
640 fConventionsListView
->DeselectAll();
641 if (fDefaultConventionsItem
!= NULL
) {
643 = fConventionsListView
->Superitem(fDefaultConventionsItem
);
644 if (superitem
!= NULL
&& !superitem
->IsExpanded())
645 fConventionsListView
->Expand(superitem
);
646 fConventionsListView
->Select(fConventionsListView
->IndexOf(
647 fDefaultConventionsItem
));
648 fConventionsListView
->ScrollToSelection();