diff --git a/src/apps/Jamfile b/src/apps/Jamfile index 62fc75d9ba..4a4d1a5273 100644 --- a/src/apps/Jamfile +++ b/src/apps/Jamfile @@ -43,6 +43,7 @@ HaikuSubInclude poorman ; HaikuSubInclude powerstatus ; HaikuSubInclude processcontroller ; HaikuSubInclude pulse ; +HaikuSubInclude readonlybootprompt ; HaikuSubInclude remotedesktop ; HaikuSubInclude resedit ; HaikuSubInclude screenshot ; diff --git a/src/apps/readonlybootprompt/BootPrompt.cpp b/src/apps/readonlybootprompt/BootPrompt.cpp new file mode 100644 index 0000000000..354e55821d --- /dev/null +++ b/src/apps/readonlybootprompt/BootPrompt.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2010, Stephan Aßmus + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "BootPrompt.h" + +#include + +#include +#include + +#include "BootPromptWindow.h" + + +int +main(int, char **) +{ + BootPromptApp app; + app.Run(); + return 0; +} + + +// #pragma mark - + + +const char* kAppSignature = "application/x-vnd.Haiku-ReadOnlyBootPrompt"; + + +BootPromptApp::BootPromptApp() + : + BApplication(kAppSignature) +{ +} + + +void +BootPromptApp::MessageReceived(BMessage* message) +{ + switch (message->what) { + case MSG_BOOT_DESKTOP: + // TODO: Exit with some value that the Bootscript can deal with. + exit(1); + break; + case MSG_RUN_INSTALLER: + // TODO: Exit with some value that the Bootscript can deal with. + exit(0); + break; + + default: + BApplication::MessageReceived(message); + } +} + + +void +BootPromptApp::AboutRequested() +{ + const char* kAuthors[] = { + "Stephan Aßmus", + NULL + }; + + BAboutWindow* aboutWindow = new BAboutWindow("ReadOnlyBootPrompt", 2010, + kAuthors); + + aboutWindow->Show(); +} + + +void +BootPromptApp::ReadyToRun() +{ + // Prompt the user to select his preferred language. + new BootPromptWindow(); +} + diff --git a/src/apps/readonlybootprompt/BootPrompt.h b/src/apps/readonlybootprompt/BootPrompt.h new file mode 100644 index 0000000000..31aa2847ff --- /dev/null +++ b/src/apps/readonlybootprompt/BootPrompt.h @@ -0,0 +1,28 @@ +/* + * Copyright 2010, Stephan Aßmus . + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef BOOT_PROMPT_APP_H +#define BOOT_PROMPT_APP_H + +#include + + +enum { + MSG_BOOT_DESKTOP = 'dktp', + MSG_RUN_INSTALLER = 'inst' +}; + +extern const char* kAppSignature; + + +class BootPromptApp : public BApplication { +public: + BootPromptApp(); + + virtual void MessageReceived(BMessage* message); + virtual void AboutRequested(); + virtual void ReadyToRun(); +}; + +#endif // BOOT_PROMPT_APP_H diff --git a/src/apps/readonlybootprompt/BootPrompt.rdef b/src/apps/readonlybootprompt/BootPrompt.rdef new file mode 100644 index 0000000000..6e42fcec1f --- /dev/null +++ b/src/apps/readonlybootprompt/BootPrompt.rdef @@ -0,0 +1,17 @@ + +resource app_signature "application/x-vnd.Haiku-ReadOnlyBootPrompt"; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + variety = B_APPV_BETA, + internal = 0, + + short_info = "ReadOnlyBootPrompt", + long_info = "ReadOnlyBootPrompt ©2010 The Haiku Project" +}; + +resource app_flags B_EXCLUSIVE_LAUNCH; + diff --git a/src/apps/readonlybootprompt/BootPromptWindow.cpp b/src/apps/readonlybootprompt/BootPromptWindow.cpp new file mode 100644 index 0000000000..58712f93bc --- /dev/null +++ b/src/apps/readonlybootprompt/BootPromptWindow.cpp @@ -0,0 +1,398 @@ +/* + * Copyright 2010, Stephan Aßmus + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "BootPromptWindow.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "BootPrompt.h" +#include "Keymap.h" +#include "KeymapListItem.h" + + +enum { + MSG_LANGUAGE_SELECTED = 'lngs', + MSG_KEYMAP_SELECTED = 'kmps' +}; + +#undef TR_CONTEXT +#define TR_CONTEXT "BootPromptWindow" + + +class LanguageItem : public BStringItem { +public: + LanguageItem(const char* label, const char* language) + : + BStringItem(label), + fLanguage(language) + { + } + + const char* Language() const + { + return fLanguage.String(); + } + +private: + BString fLanguage; +}; + + +BootPromptWindow::BootPromptWindow() + : + BWindow(BRect(0, 0, 450, 380), "", + B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_NOT_CLOSABLE + | B_AUTO_UPDATE_SIZE_LIMITS) +{ + // TODO: Remove once BLocalRoster is fixed. + be_locale_roster->GetInstalledLanguages(&fInstalledLanguages); + + fInfoTextView = new BTextView("info", be_plain_font, NULL, B_WILL_DRAW); + fInfoTextView->SetInsets(10, 10, 10, 10); + fInfoTextView->MakeEditable(false); + fInfoTextView->MakeSelectable(false); + + BScrollView* infoScrollView = new BScrollView("infoScroll", + fInfoTextView, B_WILL_DRAW, false, true); + + fDesktopButton = new BButton("", new BMessage(MSG_BOOT_DESKTOP)); + fDesktopButton->SetTarget(be_app); + fDesktopButton->MakeDefault(true); + + fInstallerButton = new BButton("", new BMessage(MSG_RUN_INSTALLER)); + fInstallerButton->SetTarget(be_app); + + fLanguagesLabelView = new BStringView("languagesLabel", ""); + fLanguagesLabelView->SetFont(be_bold_font); + fLanguagesLabelView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, + B_SIZE_UNSET)); + + fKeymapsLabelView = new BStringView("keymapsLabel", ""); + fKeymapsLabelView->SetFont(be_bold_font); + fKeymapsLabelView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, + B_SIZE_UNSET)); + + fLanguagesListView = new BListView(); + BScrollView* languagesScrollView = new BScrollView("languagesScroll", + fLanguagesListView, B_WILL_DRAW, false, true); + + fKeymapsListView = new BListView(); + BScrollView* keymapsScrollView = new BScrollView("keymapsScroll", + fKeymapsListView, B_WILL_DRAW, false, true); + + _InitCatalog(false); + _UpdateStrings(); + + float spacing = be_control_look->DefaultItemSpacing(); + + SetLayout(new BGroupLayout(B_HORIZONTAL)); + AddChild(BGroupLayoutBuilder(B_VERTICAL) + .Add(BGroupLayoutBuilder(B_VERTICAL, spacing) + .Add(infoScrollView) + .Add(BGroupLayoutBuilder(B_HORIZONTAL, spacing) + .Add(BGroupLayoutBuilder(B_VERTICAL, spacing) + .Add(fLanguagesLabelView) + .Add(languagesScrollView) + ) + .Add(BGroupLayoutBuilder(B_VERTICAL, spacing) + .Add(fKeymapsLabelView) + .Add(keymapsScrollView) + ) + ) + .SetInsets(spacing, spacing, spacing, spacing) + ) + .Add(new BSeparatorView(B_HORIZONTAL)) + .Add(BGroupLayoutBuilder(B_HORIZONTAL, spacing) + .AddGlue() + .Add(fInstallerButton) + .Add(fDesktopButton) + .SetInsets(spacing, spacing, spacing, spacing) + ) + ); + + CenterOnScreen(); + Show(); +} + + +void +BootPromptWindow::MessageReceived(BMessage* message) +{ + switch (message->what) { + case MSG_LANGUAGE_SELECTED: + if (BListItem* item = fLanguagesListView->ItemAt( + fLanguagesListView->CurrentSelection(0))) { + LanguageItem* languageItem = dynamic_cast(item); + BMessage preferredLanguages; + preferredLanguages.AddString("language", + languageItem->Language()); + be_locale_roster->SetPreferredLanguages(&preferredLanguages); + _InitCatalog(true); + } + // Calling it here is a cheap way of preventing the user to have + // no item selected. Always the current item will be selected. + _UpdateStrings(); + break; + + case MSG_KEYMAP_SELECTED: + _StoreKeymap(); + break; + + default: + BWindow::MessageReceived(message); + } +} + + +void +BootPromptWindow::_InitCatalog(bool saveSettings) +{ + // Initilialize the Locale Kit + // TODO: The below code is a work-around for not being able to + // call GetAppCatalog() more than once. + be_catalog = be_app_catalog = NULL; + // NOTE: be_catalog and be_app_catalog will point fo &fCatalog! + + be_locale->GetAppCatalog(&fCatalog); + + // Generate a settings file + // TODO: This should not be necessary. + // be_locale_roster->SetPreferredLanguages() should take care of things + if (!saveSettings) + return; + + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK + || path.Append("Locale settings") != B_OK) { + return; + } + + BMessage settings; + + BFile file; + if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK) + settings.Unflatten(&file); + + BString language; + if (fCatalog.GetLanguage(&language) == B_OK) { + settings.RemoveName("language"); + settings.AddString("language", language.String()); + } + + settings.RemoveName("country"); + BCountry country(language.String(), language.ToUpper()); + settings.AddString("country", country.Code()); + + if (file.SetTo(path.Path(), B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY) + != B_OK + || settings.Flatten(&file) != B_OK) { + fprintf(stderr, "Failed to write Local Kit settings!\n"); + } +} + + +void +BootPromptWindow::_UpdateStrings() +{ + SetTitle(TR("Welcome to Haiku")); + + const char* infoText = TR( + "Welcome to Haiku!\n\n" + + "Do you wish to want to run the Installer or continue booting " + "to the Desktop?\n\n" + + "Please select your preferred language and keyboard layout from " + "the list below." + ); + + fInfoTextView->SetText(infoText); + + fDesktopButton->SetLabel(TR("Desktop")); + fInstallerButton->SetLabel(TR("Installer")); + + fLanguagesLabelView->SetText(TR("Language")); + fKeymapsLabelView->SetText(TR("Keymap")); + + _PopulateLanguages(); + _PopulateKeymaps(); +} + + +void +BootPromptWindow::_PopulateLanguages() +{ + // Disable sending the selection message while we change the selection. + fLanguagesListView->SetSelectionMessage(NULL); + + // Clear the list view first + while (BListItem* item = fLanguagesListView->RemoveItem( + fLanguagesListView->CountItems() - 1)) { + delete item; + } + + // Get current first preferred language of the user + BMessage preferredLanguages; + be_locale_roster->GetPreferredLanguages(&preferredLanguages); + const char* firstPreferredLanguage; + if (preferredLanguages.FindString("language", &firstPreferredLanguage) + != B_OK) { + // Fall back to built-in language of this application. + firstPreferredLanguage = "en"; + } + +// TODO: Use this API instead once it's ready. +// BMessage installedCatalogs; +// be_locale_roster->GetInstalledCatalogs(&installedCatalogs); +// installedCatalogs.PrintToStream(); + +// TODO: BLocaleRoster uses static variables!! Fix this! Or else one can only +// call this once! +// // Get the list of all known languages +// BMessage installedLanguages; +// be_locale_roster->GetInstalledLanguages(&installedLanguages); + + // Try to instantiate a BCatalog for each language, it will only work + // for translations of this application. So the list of languages will be + // limited to catalogs written for this application, which is on purpose! + const char* languageString; + for (int32 i = 0; + fInstalledLanguages.FindString("langs", i, &languageString) == B_OK; + i++) { + BCatalog catalog("x-vnd.Haiku-ReadOnlyBootPrompt", languageString); + if (catalog.InitCheck() == B_OK) { + BLanguage* language; + if (be_locale_roster->GetLanguage(&language, + BString(languageString)) == B_OK) { + BString name; + language->GetName(&name); + LanguageItem* item = new LanguageItem(name.String(), + languageString); + fLanguagesListView->AddItem(item); + // Select this item if it is the first preferred language + if (strcmp(firstPreferredLanguage, languageString) == 0) { + fLanguagesListView->Select( + fLanguagesListView->CountItems() - 1); + } + } else + printf("failed to get BLanguage for %s\n", languageString); + } + } + + // Re-enable sending the selection message. + fLanguagesListView->SetSelectionMessage( + new BMessage(MSG_LANGUAGE_SELECTED)); +} + + +void +BootPromptWindow::_PopulateKeymaps() +{ + // Disable sending the selection message while we change the selection. + fKeymapsListView->SetSelectionMessage(NULL); + + // Clean the list view first + while (BListItem* item = fKeymapsListView->RemoveItem( + fKeymapsListView->CountItems() - 1)) { + delete item; + } + + // Get the name of the current keymap, so we can mark the correct entry + // in the list view. + BString currentKeymapName; + entry_ref ref; + if (_GetCurrentKeymapRef(ref) == B_OK) { + BNode node(&ref); + node.ReadAttrString("keymap:name", ¤tKeymapName); + } + + // TODO: common keymaps! + BPath path; + if (find_directory(B_SYSTEM_DATA_DIRECTORY, &path) != B_OK + || path.Append("Keymaps") != B_OK) { + return; + } + + // Populate the list + BDirectory directory; + if (directory.SetTo(path.Path()) == B_OK) { + while (directory.GetNextRef(&ref) == B_OK) { + fKeymapsListView->AddItem(new KeymapListItem(ref)); + if (currentKeymapName == ref.name) + fKeymapsListView->Select(fKeymapsListView->CountItems() - 1); + } + } + + fKeymapsListView->ScrollToSelection(); + + // Re-enable sending the selection message. + fKeymapsListView->SetSelectionMessage( + new BMessage(MSG_KEYMAP_SELECTED)); +} + + +void +BootPromptWindow::_StoreKeymap() const +{ + KeymapListItem* item = dynamic_cast( + fKeymapsListView->ItemAt(fKeymapsListView->CurrentSelection(0))); + if (item == NULL) + return; + + // Load and use the new keymap + Keymap keymap; + if (keymap.Load(item->EntryRef()) != B_OK) { + fprintf(stderr, "Failed to load new keymap file (%s).\n", + item->EntryRef().name); + return; + } + + // Get entry_ref to the Key_map file in the user settings. + entry_ref ref; + if (_GetCurrentKeymapRef(ref) != B_OK) { + fprintf(stderr, "Failed to get ref to user keymap file.\n"); + return; + } + + if (keymap.Save(ref) != B_OK) { + fprintf(stderr, "Failed to save new keymap file (%s).\n", + item->EntryRef().name); + return; + } + + keymap.Use(); +} + + +status_t +BootPromptWindow::_GetCurrentKeymapRef(entry_ref& ref) const +{ + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK + || path.Append("Key_map") != B_OK) { + return B_ERROR; + } + + return get_ref_for_path(path.Path(), &ref); +} + diff --git a/src/apps/readonlybootprompt/BootPromptWindow.h b/src/apps/readonlybootprompt/BootPromptWindow.h new file mode 100644 index 0000000000..0404dfd00f --- /dev/null +++ b/src/apps/readonlybootprompt/BootPromptWindow.h @@ -0,0 +1,46 @@ +/* + * Copyright 2010, Stephan Aßmus . + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef BOOT_PROMPT_WINDOW_H +#define BOOT_PROMPT_WINDOW_H + +#include +#include +#include + +class BButton; +class BListView; +class BStringView; +class BTextView; + + +class BootPromptWindow : public BWindow { +public: + BootPromptWindow(); + + virtual void MessageReceived(BMessage* message); + +private: + void _InitCatalog(bool saveSettings); + void _UpdateStrings(); + void _PopulateLanguages(); + void _PopulateKeymaps(); + void _StoreKeymap() const; + status_t _GetCurrentKeymapRef(entry_ref& ref) const; + +private: + BCatalog fCatalog; + BTextView* fInfoTextView; + BStringView* fLanguagesLabelView; + BListView* fLanguagesListView; + BStringView* fKeymapsLabelView; + BListView* fKeymapsListView; + BButton* fDesktopButton; + BButton* fInstallerButton; + + // TODO: Should not be needed, see TODO in _PopulateLanguages() + BMessage fInstalledLanguages; +}; + +#endif // BOOT_PROMPT_WINDOW_H diff --git a/src/apps/readonlybootprompt/Jamfile b/src/apps/readonlybootprompt/Jamfile new file mode 100644 index 0000000000..b63981e546 --- /dev/null +++ b/src/apps/readonlybootprompt/Jamfile @@ -0,0 +1,24 @@ +SubDir HAIKU_TOP src apps readonlybootprompt ; + +UsePrivateHeaders interface shared ; + +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src preferences keymap ] ; + +Application ReadOnlyBootPrompt : + BootPrompt.cpp + BootPromptWindow.cpp + Keymap.cpp + KeymapListItem.cpp + : be libshared.a $(TARGET_LIBSTDC++) liblocale.so + : BootPrompt.rdef +; + +DoCatalogs ReadOnlyBootPrompt : + x-vnd.Haiku-ReadOnlyBootPrompt + : + BootPrompt.cpp + BootPromptWindow.cpp + : en.catalog + : de.catkeys +; +