hrev47919 adds 2 changesets to branch 'master' old head: 83f46c7198f03c981cb985f8901744ef53b8ab6d new head: 8f03a0f9f2645bc296173abce96cc8547a977b6e overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=8f03a0f+%5E83f46c7 ---------------------------------------------------------------------------- 3e3d0ef: HaikuDepot: Limit language selection for account creation For the time being, there is a limited amount of supported languages when creating accounts, reflect this in the UI and use a BMenuField. Creating accounts with other languages fails, the error reporting was not ideal and could be improved. The server responded with "object not found", which was reported in the alert, but the response actually contains the object which was not found (NaturalLanguageCode). 8f03a0f: HaikuDepot: Restore logged in user across sessions. * Store the username in the app settings. The password was already stored in the keyring. Restore the username upon next launch. * Display the logged in user in the main window. * Added "Log out" menu entry. * When the password could not be retrieved from the keyring (also because the user rejects the keyring dialog), unset the username. * Allow unsetting the username by passing an empty name. [ Stephan Aßmus <superstippi@xxxxxx> ] ---------------------------------------------------------------------------- 9 files changed, 219 insertions(+), 28 deletions(-) src/apps/haikudepot/model/Model.cpp | 60 ++++++++++++++++++---- src/apps/haikudepot/model/Model.h | 20 +++++++- src/apps/haikudepot/model/WebAppInterface.h | 3 ++ src/apps/haikudepot/ui/FilterView.cpp | 36 +++++++++++-- src/apps/haikudepot/ui/FilterView.h | 9 +++- src/apps/haikudepot/ui/MainWindow.cpp | 67 ++++++++++++++++++++++--- src/apps/haikudepot/ui/MainWindow.h | 3 ++ src/apps/haikudepot/ui/UserLoginWindow.cpp | 45 +++++++++++++++-- src/apps/haikudepot/ui/UserLoginWindow.h | 4 +- ############################################################################ Commit: 3e3d0effdc47debfd583da23fbb4000e453d9bc9 URL: http://cgit.haiku-os.org/haiku/commit/?id=3e3d0ef Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Sep 27 22:29:50 2014 UTC HaikuDepot: Limit language selection for account creation For the time being, there is a limited amount of supported languages when creating accounts, reflect this in the UI and use a BMenuField. Creating accounts with other languages fails, the error reporting was not ideal and could be improved. The server responded with "object not found", which was reported in the alert, but the response actually contains the object which was not found (NaturalLanguageCode). ---------------------------------------------------------------------------- diff --git a/src/apps/haikudepot/ui/UserLoginWindow.cpp b/src/apps/haikudepot/ui/UserLoginWindow.cpp index bb47b53..a26ac96 100644 --- a/src/apps/haikudepot/ui/UserLoginWindow.cpp +++ b/src/apps/haikudepot/ui/UserLoginWindow.cpp @@ -15,6 +15,8 @@ #include <Catalog.h> #include <Button.h> #include <LayoutBuilder.h> +#include <MenuField.h> +#include <PopUpMenu.h> #include <TabView.h> #include <TextControl.h> @@ -31,6 +33,7 @@ enum { MSG_SEND = 'send', MSG_TAB_SELECTED = 'tbsl', MSG_CAPTCHA_OBTAINED = 'cpob', + MSG_LANGUAGE_SELECTED = 'lngs', }; @@ -59,12 +62,26 @@ private: }; +static void +add_languages_to_menu(const StringList& languages, BMenu* menu) +{ + for (int i = 0; i < languages.CountItems(); i++) { + const BString& language = languages.ItemAtFast(i); + BMessage* message = new BMessage(MSG_LANGUAGE_SELECTED); + message->AddString("code", language); + BMenuItem* item = new BMenuItem(language, message); + menu->AddItem(item); + } +} + + UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model) : BWindow(frame, B_TRANSLATE_SYSTEM_NAME("Log in"), B_FLOATING_WINDOW_LOOK, B_FLOATING_SUBSET_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_RESIZABLE | B_NOT_ZOOMABLE), + fPreferredLanguage(model.PreferredLanguage()), fModel(model), fMode(NONE), fWorkerThread(-1) @@ -73,14 +90,30 @@ UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model) fUsernameField = new BTextControl(B_TRANSLATE("User name:"), "", NULL); fPasswordField = new BTextControl(B_TRANSLATE("Pass phrase:"), "", NULL); + fPasswordField->TextView()->HideTyping(true); fNewUsernameField = new BTextControl(B_TRANSLATE("User name:"), "", NULL); fNewPasswordField = new BTextControl(B_TRANSLATE("Pass phrase:"), "", NULL); + fNewPasswordField->TextView()->HideTyping(true); fRepeatPasswordField = new BTextControl(B_TRANSLATE("Repeat pass phrase:"), "", NULL); - fLanguageCodeField = new BTextControl(B_TRANSLATE("Language code:"), - model.PreferredLanguage(), NULL); + fRepeatPasswordField->TextView()->HideTyping(true); + + // Construct languages popup + BPopUpMenu* languagesMenu = new BPopUpMenu(B_TRANSLATE("Language")); + fLanguageCodeField = new BMenuField("language", + B_TRANSLATE("Preferred language:"), languagesMenu); + + add_languages_to_menu(fModel.SupportedLanguages(), languagesMenu); + languagesMenu->SetTargetForItems(this); + + BMenuItem* defaultItem = languagesMenu->ItemAt( + fModel.SupportedLanguages().IndexOf(fPreferredLanguage)); + if (defaultItem != NULL) + defaultItem->SetMarked(true); + + fEmailField = new BTextControl(B_TRANSLATE("Email address:"), "", NULL); fCaptchaView = new BitmapView("captcha view"); fCaptchaResultField = new BTextControl("", "", NULL); @@ -104,7 +137,7 @@ UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model) .AddTextControl(fNewPasswordField, 0, 1) .AddTextControl(fRepeatPasswordField, 0, 2) .AddTextControl(fEmailField, 0, 3) - .AddTextControl(fLanguageCodeField, 0, 4) + .AddMenuField(fLanguageCodeField, 0, 4) .Add(fCaptchaView, 0, 5) .Add(fCaptchaResultField, 1, 5) @@ -190,6 +223,10 @@ UserLoginWindow::MessageReceived(BMessage* message) } break; + case MSG_LANGUAGE_SELECTED: + message->FindString("code", &fPreferredLanguage); + break; + default: BWindow::MessageReceived(message); break; @@ -448,7 +485,7 @@ UserLoginWindow::_CreateAccountThread() BString email(fEmailField->Text()); BString captchaToken(fCaptchaToken); BString captchaResponse(fCaptchaResultField->Text()); - BString languageCode(fLanguageCodeField->Text()); + BString languageCode(fPreferredLanguage); Unlock(); diff --git a/src/apps/haikudepot/ui/UserLoginWindow.h b/src/apps/haikudepot/ui/UserLoginWindow.h index a178881..66f0e53 100644 --- a/src/apps/haikudepot/ui/UserLoginWindow.h +++ b/src/apps/haikudepot/ui/UserLoginWindow.h @@ -12,6 +12,7 @@ class BButton; +class BMenuField; class BTabView; class BTextControl; class BitmapView; @@ -63,7 +64,7 @@ private: BTextControl* fNewPasswordField; BTextControl* fRepeatPasswordField; BTextControl* fEmailField; - BTextControl* fLanguageCodeField; + BMenuField* fLanguageCodeField; BitmapView* fCaptchaView; BTextControl* fCaptchaResultField; @@ -72,6 +73,7 @@ private: BString fCaptchaToken; BitmapRef fCaptchaImage; + BString fPreferredLanguage; Model& fModel; ############################################################################ Revision: hrev47919 Commit: 8f03a0f9f2645bc296173abce96cc8547a977b6e URL: http://cgit.haiku-os.org/haiku/commit/?id=8f03a0f Author: Stephan Aßmus <superstippi@xxxxxx> Date: Sat Sep 27 22:33:20 2014 UTC HaikuDepot: Restore logged in user across sessions. * Store the username in the app settings. The password was already stored in the keyring. Restore the username upon next launch. * Display the logged in user in the main window. * Added "Log out" menu entry. * When the password could not be retrieved from the keyring (also because the user rejects the keyring dialog), unset the username. * Allow unsetting the username by passing an empty name. ---------------------------------------------------------------------------- diff --git a/src/apps/haikudepot/model/Model.cpp b/src/apps/haikudepot/model/Model.cpp index 1166117..0560456 100644 --- a/src/apps/haikudepot/model/Model.cpp +++ b/src/apps/haikudepot/model/Model.cpp @@ -30,14 +30,19 @@ static const char* kHaikuDepotKeyring = "HaikuDepot"; -// #pragma mark - PackageFilters +PackageFilter::~PackageFilter() +{ +} -PackageFilter::~PackageFilter() +ModelListener::~ModelListener() { } +// #pragma mark - PackageFilters + + class AnyFilter : public PackageFilter { public: virtual bool AcceptsPackage(const PackageInfoRef& package) const @@ -368,6 +373,13 @@ Model::~Model() } +bool +Model::AddListener(const ModelListenerRef& listener) +{ + return fListeners.Add(listener); +} + + PackageList Model::CreatePackageList() const { @@ -661,14 +673,27 @@ Model::StopPopulatingAllPackages() void -Model::SetUser(const BString& username) +Model::SetUsername(BString username) { - BPasswordKey key; - BKeyStore keyStore; - if (keyStore.GetKey(kHaikuDepotKeyring, B_KEY_TYPE_PASSWORD, username, - key) == B_OK) { - SetAuthorization(username, key.Password(), false); + BString password; + if (username.Length() > 0) { + BPasswordKey key; + BKeyStore keyStore; + if (keyStore.GetKey(kHaikuDepotKeyring, B_KEY_TYPE_PASSWORD, username, + key) == B_OK) { + password = key.Password(); + } else { + username = ""; + } } + SetAuthorization(username, password, false); +} + + +const BString& +Model::Username() const +{ + return fWebAppInterface.Username(); } @@ -676,7 +701,7 @@ void Model::SetAuthorization(const BString& username, const BString& password, bool storePassword) { - if (storePassword) { + if (storePassword && username.Length() > 0 && password.Length() > 0) { BPasswordKey key(password, B_KEY_PURPOSE_WEB, username); BKeyStore keyStore; keyStore.AddKeyring(kHaikuDepotKeyring); @@ -685,6 +710,8 @@ Model::SetAuthorization(const BString& username, const BString& password, BAutolock locker(&fLock); fWebAppInterface.SetAuthorization(username, password); + + _NotifyAuthorizationChanged(); } @@ -1146,3 +1173,18 @@ Model::_HasNativeIcon(const BMessage& message) const } return false; } + + +// #pragma mark - listener notification methods + + +void +Model::_NotifyAuthorizationChanged() +{ + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) { + const ModelListenerRef& listener = fListeners.ItemAtFast(i); + if (listener.Get() != NULL) + listener->AuthorizationChanged(); + } +} + diff --git a/src/apps/haikudepot/model/Model.h b/src/apps/haikudepot/model/Model.h index d47aa7f..4d7b21f 100644 --- a/src/apps/haikudepot/model/Model.h +++ b/src/apps/haikudepot/model/Model.h @@ -25,6 +25,17 @@ public: typedef BReference<PackageFilter> PackageFilterRef; +class ModelListener : public BReferenceable { +public: + virtual ~ModelListener(); + + virtual void AuthorizationChanged() = 0; +}; + +typedef BReference<ModelListener> ModelListenerRef; +typedef List<ModelListenerRef, false> ModelListenerList; + + class Model { public: Model(); @@ -33,6 +44,8 @@ public: BLocker* Lock() { return &fLock; } + bool AddListener(const ModelListenerRef& listener); + // !Returns new PackageInfoList from current parameters PackageList CreatePackageList() const; @@ -110,7 +123,8 @@ public: const BString& PreferredLanguage() const { return fPreferredLanguage; } - void SetUser(const BString& username); + void SetUsername(BString username); + const BString& Username() const; void SetAuthorization(const BString& username, const BString& password, bool storePassword); @@ -139,6 +153,8 @@ private: int32 scaledWidth, bool fromCacheOnly); + void _NotifyAuthorizationChanged(); + private: BLocker fLock; @@ -182,6 +198,8 @@ private: BString fPreferredLanguage; WebAppInterface fWebAppInterface; + + ModelListenerList fListeners; }; diff --git a/src/apps/haikudepot/model/WebAppInterface.h b/src/apps/haikudepot/model/WebAppInterface.h index 3407b25..b2b8262 100644 --- a/src/apps/haikudepot/model/WebAppInterface.h +++ b/src/apps/haikudepot/model/WebAppInterface.h @@ -28,6 +28,9 @@ public: void SetAuthorization(const BString& username, const BString& password); + const BString& Username() const + { return fUsername; } + void SetPreferredLanguage(const BString& language); void SetArchitecture(const BString& architecture); diff --git a/src/apps/haikudepot/ui/FilterView.cpp b/src/apps/haikudepot/ui/FilterView.cpp index b57264b..ef52e08 100644 --- a/src/apps/haikudepot/ui/FilterView.cpp +++ b/src/apps/haikudepot/ui/FilterView.cpp @@ -15,6 +15,7 @@ #include <MenuItem.h> #include <Messenger.h> #include <PopUpMenu.h> +#include <StringView.h> #include <TextControl.h> #include "Model.h" @@ -37,16 +38,23 @@ add_categories_to_menu(const CategoryList& categories, BMenu* menu) } +static void +set_small_font(BView* view) +{ + BFont font; + view->GetFont(&font); + font.SetSize(ceilf(font.Size() * 0.8)); + view->SetFont(&font); +} + + static BCheckBox* create_check_box(const char* label, const char* name) { BMessage* message = new BMessage(MSG_FILTER_SELECTED); message->AddString("name", name); BCheckBox* checkBox = new BCheckBox(label, message); - BFont font; - checkBox->GetFont(&font); - font.SetSize(ceilf(font.Size() * 0.75)); - checkBox->SetFont(&font); + set_small_font(checkBox); return checkBox; } @@ -90,6 +98,11 @@ FilterView::FilterView() fSourceCodeCheckBox = create_check_box( B_TRANSLATE("Source code"), "source code"); + // Logged in user label + fUsername = new BStringView("logged in user", ""); + set_small_font(fUsername); + fUsername->SetHighColor(80, 80, 80); + // Build layout BLayoutBuilder::Group<>(this) .AddGroup(B_HORIZONTAL) @@ -107,6 +120,7 @@ FilterView::FilterView() .Add(fDevelopmentCheckBox) .Add(fSourceCodeCheckBox) .AddGlue(0.5f) + .Add(fUsername) .End() .SetInsets(B_USE_DEFAULT_SPACING) @@ -200,3 +214,17 @@ FilterView::AdoptCheckmarks(const Model& model) fSourceCodeCheckBox->SetValue(model.ShowSourcePackages()); } + +void +FilterView::SetUsername(const BString& username) +{ + BString label; + if (username.Length() == 0) { + label = B_TRANSLATE("Not logged in"); + } else { + label = B_TRANSLATE("Logged in as %User%"); + label.ReplaceAll("%User%", username); + } + fUsername->SetText(label); +} + diff --git a/src/apps/haikudepot/ui/FilterView.h b/src/apps/haikudepot/ui/FilterView.h index 78ae76a..81e6a6b 100644 --- a/src/apps/haikudepot/ui/FilterView.h +++ b/src/apps/haikudepot/ui/FilterView.h @@ -10,6 +10,7 @@ class BCheckBox; class BMenuField; +class BStringView; class BTextControl; class Model; @@ -30,8 +31,10 @@ public: virtual void AttachedToWindow(); virtual void MessageReceived(BMessage* message); - virtual void AdoptModel(const Model& model); - virtual void AdoptCheckmarks(const Model& model); + void AdoptModel(const Model& model); + void AdoptCheckmarks(const Model& model); + + void SetUsername(const BString& username); private: BMenuField* fShowField; @@ -42,6 +45,8 @@ private: BCheckBox* fInstalledCheckBox; BCheckBox* fDevelopmentCheckBox; BCheckBox* fSourceCodeCheckBox; + + BStringView* fUsername; }; #endif // FILTER_VIEW_H diff --git a/src/apps/haikudepot/ui/MainWindow.cpp b/src/apps/haikudepot/ui/MainWindow.cpp index ccf09a3..0ff7612 100644 --- a/src/apps/haikudepot/ui/MainWindow.cpp +++ b/src/apps/haikudepot/ui/MainWindow.cpp @@ -53,12 +53,14 @@ enum { - MSG_MODEL_WORKER_DONE = 'mmwd', - MSG_REFRESH_DEPOTS = 'mrdp', - MSG_LOG_IN = 'lgin', - MSG_PACKAGE_STATE_CHANGED = 'mpsc', - MSG_SHOW_SOURCE_PACKAGES = 'ssrc', - MSG_SHOW_DEVELOP_PACKAGES = 'sdvl' + MSG_MODEL_WORKER_DONE = 'mmwd', + MSG_REFRESH_DEPOTS = 'mrdp', + MSG_LOG_IN = 'lgin', + MSG_LOG_OUT = 'lgot', + MSG_AUTHORIZATION_CHANGED = 'athc', + MSG_PACKAGE_STATE_CHANGED = 'mpsc', + MSG_SHOW_SOURCE_PACKAGES = 'ssrc', + MSG_SHOW_DEVELOP_PACKAGES = 'sdvl' }; @@ -83,11 +85,31 @@ struct RefreshWorkerParameters { }; +class MessageModelListener : public ModelListener { +public: + MessageModelListener(const BMessenger& messenger) + : + fMessenger(messenger) + { + } + + virtual void AuthorizationChanged() + { + if (fMessenger.IsValid()) + fMessenger.SendMessage(MSG_AUTHORIZATION_CHANGED); + } + +private: + BMessenger fMessenger; +}; + + MainWindow::MainWindow(BRect frame, const BMessage& settings) : BWindow(frame, B_TRANSLATE_SYSTEM_NAME("HaikuDepot"), B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), + fModelListener(new MessageModelListener(BMessenger(this)), true), fTerminating(false), fModelWorker(B_BAD_THREAD_ID) { @@ -117,6 +139,8 @@ MainWindow::MainWindow(BRect frame, const BMessage& settings) fSplitView->SetCollapsible(0, false); fSplitView->SetCollapsible(1, false); + fModel.AddListener(fModelListener); + // Restore settings BMessage columnSettings; if (settings.FindMessage("column settings", &columnSettings) == B_OK) @@ -128,6 +152,13 @@ MainWindow::MainWindow(BRect frame, const BMessage& settings) if (settings.FindBool("show source packages", &showOption) == B_OK) fModel.SetShowSourcePackages(showOption); + BString username; + if (settings.FindString("username", &username) == B_OK + && username.Length() > 0) { + fModel.SetUsername(username); + } + + // start worker threads BPackageRoster().StartWatching(this, B_WATCH_PACKAGE_INSTALLATION_LOCATIONS); @@ -212,6 +243,14 @@ MainWindow::MessageReceived(BMessage* message) _OpenLoginWindow(); break; + case MSG_LOG_OUT: + fModel.SetUsername(""); + break; + + case MSG_AUTHORIZATION_CHANGED: + _UpdateAuthorization(); + break; + case MSG_SHOW_SOURCE_PACKAGES: { BAutolock locker(fModel.Lock()); @@ -358,6 +397,8 @@ MainWindow::StoreSettings(BMessage& settings) const settings.AddBool("show develop packages", fModel.ShowDevelopPackages()); settings.AddBool("show source packages", fModel.ShowSourcePackages()); + + settings.AddString("username", fModel.Username()); } @@ -401,8 +442,12 @@ MainWindow::_BuildMenu(BMenuBar* menuBar) BMenu* menu = new BMenu(B_TRANSLATE("Tools")); menu->AddItem(new BMenuItem(B_TRANSLATE("Refresh depots"), new BMessage(MSG_REFRESH_DEPOTS))); - menu->AddItem(new BMenuItem(B_TRANSLATE("Log in"), + menu->AddSeparatorItem(); + menu->AddItem(new BMenuItem(B_TRANSLATE("Log in" B_UTF8_ELLIPSIS), new BMessage(MSG_LOG_IN))); + fLogOutItem = new BMenuItem(B_TRANSLATE("Log out"), + new BMessage(MSG_LOG_OUT)); + menu->AddItem(fLogOutItem); menuBar->AddItem(menu); // menu = new BMenu(B_TRANSLATE("Options")); @@ -858,3 +903,11 @@ MainWindow::_OpenLoginWindow() window->Show(); } + +void +MainWindow::_UpdateAuthorization() +{ + BString username(fModel.Username()); + fLogOutItem->SetEnabled(username.Length() > 0); + fFilterView->SetUsername(username); +} diff --git a/src/apps/haikudepot/ui/MainWindow.h b/src/apps/haikudepot/ui/MainWindow.h index b2d26e4..7e1bb1b 100644 --- a/src/apps/haikudepot/ui/MainWindow.h +++ b/src/apps/haikudepot/ui/MainWindow.h @@ -72,16 +72,19 @@ private: const char* message); void _OpenLoginWindow(); + void _UpdateAuthorization(); private: FilterView* fFilterView; PackageListView* fPackageListView; PackageInfoView* fPackageInfoView; BSplitView* fSplitView; + BMenuItem* fLogOutItem; BMenuItem* fShowDevelopPackagesItem; BMenuItem* fShowSourcePackagesItem; Model fModel; + ModelListenerRef fModelListener; PackageList fVisiblePackages; bool fTerminating;