diff --git a/src/apps/haikudepot/HaikuDepotConstants.h b/src/apps/haikudepot/HaikuDepotConstants.h index 752869e0ce..9dc8c062f5 100644 --- a/src/apps/haikudepot/HaikuDepotConstants.h +++ b/src/apps/haikudepot/HaikuDepotConstants.h @@ -6,20 +6,23 @@ #define HAIKU_DEPOT_CONSTANTS_H enum { - MSG_MAIN_WINDOW_CLOSED = 'mwcl', - MSG_PACKAGE_SELECTED = 'pkgs', - MSG_PACKAGE_WORKER_BUSY = 'pkwb', - MSG_PACKAGE_WORKER_IDLE = 'pkwi', - MSG_ADD_VISIBLE_PACKAGES = 'avpk', - MSG_UPDATE_SELECTED_PACKAGE = 'uspk', - MSG_CLIENT_TOO_OLD = 'oldc', - MSG_NETWORK_TRANSPORT_ERROR = 'nett', - MSG_SERVER_ERROR = 'svre', - MSG_SERVER_DATA_CHANGED = 'svdc', - MSG_ALERT_SIMPLE_ERROR = 'nser', - MSG_DID_ADD_USER_RATING = 'adur', - MSG_DID_UPDATE_USER_RATING = 'upur', - MSG_LANGUAGE_SELECTED = 'lngs' + MSG_MAIN_WINDOW_CLOSED = 'mwcl', + MSG_PACKAGE_SELECTED = 'pkgs', + MSG_PACKAGE_WORKER_BUSY = 'pkwb', + MSG_PACKAGE_WORKER_IDLE = 'pkwi', + MSG_ADD_VISIBLE_PACKAGES = 'avpk', + MSG_UPDATE_SELECTED_PACKAGE = 'uspk', + MSG_CLIENT_TOO_OLD = 'oldc', + MSG_NETWORK_TRANSPORT_ERROR = 'nett', + MSG_SERVER_ERROR = 'svre', + MSG_SERVER_DATA_CHANGED = 'svdc', + MSG_ALERT_SIMPLE_ERROR = 'nser', + MSG_DID_ADD_USER_RATING = 'adur', + MSG_DID_UPDATE_USER_RATING = 'upur', + MSG_LANGUAGE_SELECTED = 'lngs', + MSG_VIEW_LATEST_USER_USAGE_CONDITIONS = 'vluc', + MSG_USER_USAGE_CONDITIONS_DATA = 'uucd', + MSG_USER_USAGE_CONDITIONS_ERROR = 'uuce' }; diff --git a/src/apps/haikudepot/server/WebAppInterface.cpp b/src/apps/haikudepot/server/WebAppInterface.cpp index 218e14c470..326ddd9bd1 100644 --- a/src/apps/haikudepot/server/WebAppInterface.cpp +++ b/src/apps/haikudepot/server/WebAppInterface.cpp @@ -693,31 +693,44 @@ status_t WebAppInterface::CreateUser(const BString& nickName, const BString& passwordClear, const BString& email, const BString& captchaToken, const BString& captchaResponse, - const BString& languageCode, BMessage& message) + const BString& languageCode, const BString& userUsageConditionsCode, + BMessage& message) { - JsonBuilder builder; - builder - .AddValue("jsonrpc", "2.0") - .AddValue("id", ++fRequestIndex) - .AddValue("method", "createUser") - .AddArray("params") - .AddObject() - .AddValue("nickname", nickName) - .AddValue("passwordClear", passwordClear); + // BHttpRequest later takes ownership of this. + BMallocIO* requestEnvelopeData = new BMallocIO(); + BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData); - if (!email.IsEmpty()) - builder.AddValue("email", email); + requestEnvelopeWriter.WriteObjectStart(); + _WriteStandardJsonRpcEnvelopeValues(requestEnvelopeWriter, "createUser"); + requestEnvelopeWriter.WriteObjectName("params"); + requestEnvelopeWriter.WriteArrayStart(); - builder.AddValue("captchaToken", captchaToken) - .AddValue("captchaResponse", captchaResponse) - .AddValue("naturalLanguageCode", languageCode) - .EndObject() - .EndArray() - ; + requestEnvelopeWriter.WriteObjectStart(); - BString jsonString = builder.End(); + requestEnvelopeWriter.WriteObjectName("nickname"); + requestEnvelopeWriter.WriteString(nickName.String()); + requestEnvelopeWriter.WriteObjectName("passwordClear"); + requestEnvelopeWriter.WriteString(passwordClear.String()); + requestEnvelopeWriter.WriteObjectName("captchaToken"); + requestEnvelopeWriter.WriteString(captchaToken.String()); + requestEnvelopeWriter.WriteObjectName("captchaResponse"); + requestEnvelopeWriter.WriteString(captchaResponse.String()); + requestEnvelopeWriter.WriteObjectName("naturalLanguageCode"); + requestEnvelopeWriter.WriteString(languageCode.String()); + requestEnvelopeWriter.WriteObjectName("userUsageConditionsCode"); + requestEnvelopeWriter.WriteString(userUsageConditionsCode.String()); - return _SendJsonRequest("user", jsonString, 0, message); + if (!email.IsEmpty()) { + requestEnvelopeWriter.WriteObjectName("email"); + requestEnvelopeWriter.WriteString(email.String()); + } + + requestEnvelopeWriter.WriteObjectEnd(); + requestEnvelopeWriter.WriteArrayEnd(); + requestEnvelopeWriter.WriteObjectEnd(); + + return _SendJsonRequest("user", requestEnvelopeData, + _LengthAndSeekToZero(requestEnvelopeData), 0, message); } diff --git a/src/apps/haikudepot/server/WebAppInterface.h b/src/apps/haikudepot/server/WebAppInterface.h index 36246235f4..0feaf496f1 100644 --- a/src/apps/haikudepot/server/WebAppInterface.h +++ b/src/apps/haikudepot/server/WebAppInterface.h @@ -106,6 +106,7 @@ public: const BString& captchaToken, const BString& captchaResponse, const BString& languageCode, + const BString& userUsageConditionsCode, BMessage& message); status_t AuthenticateUser(const BString& nickName, diff --git a/src/apps/haikudepot/ui/MainWindow.cpp b/src/apps/haikudepot/ui/MainWindow.cpp index ca38dac563..5d9adf9c6e 100644 --- a/src/apps/haikudepot/ui/MainWindow.cpp +++ b/src/apps/haikudepot/ui/MainWindow.cpp @@ -68,7 +68,6 @@ enum { MSG_PACKAGE_CHANGED = 'pchd', MSG_WORK_STATUS_CHANGE = 'wsch', MSG_WORK_STATUS_CLEAR = 'wscl', - MSG_VIEW_LATEST_USER_USAGE_CONDITIONS = 'vluc', MSG_SHOW_FEATURED_PACKAGES = 'sofp', MSG_SHOW_AVAILABLE_PACKAGES = 'savl', @@ -740,10 +739,11 @@ MainWindow::_BuildUserMenu(BMenuBar* menuBar) new BMessage(MSG_LOG_OUT)); fUserMenu->AddItem(fLogOutItem); - fLogOutItem = new BMenuItem(B_TRANSLATE("View latest user usage conditions" - B_UTF8_ELLIPSIS), - new BMessage(MSG_VIEW_LATEST_USER_USAGE_CONDITIONS)); - fUserMenu->AddItem(fLogOutItem); + BMenuItem *latestUserUsageConditionsMenuItem = + new BMenuItem(B_TRANSLATE("View latest user usage conditions" + B_UTF8_ELLIPSIS), + new BMessage(MSG_VIEW_LATEST_USER_USAGE_CONDITIONS)); + fUserMenu->AddItem(latestUserUsageConditionsMenuItem); menuBar->AddItem(fUserMenu); } @@ -1349,6 +1349,6 @@ void MainWindow::_ViewLatestUserUsageConditions() { UserUsageConditionsWindow* window = new UserUsageConditionsWindow( - this, BRect(0, 0, 500, 400), fModel, LATEST); + fModel, LATEST); window->Show(); -} \ No newline at end of file +} diff --git a/src/apps/haikudepot/ui/UserLoginWindow.cpp b/src/apps/haikudepot/ui/UserLoginWindow.cpp index 6b9eea3e92..b28cfffc21 100644 --- a/src/apps/haikudepot/ui/UserLoginWindow.cpp +++ b/src/apps/haikudepot/ui/UserLoginWindow.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -22,17 +23,27 @@ #include #include +#include "AppUtils.h" #include "BitmapView.h" #include "HaikuDepotConstants.h" #include "LanguageMenuUtils.h" +#include "LinkView.h" #include "Model.h" #include "TabView.h" +#include "UserUsageConditions.h" +#include "UserUsageConditionsWindow.h" #include "WebAppInterface.h" #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "UserLoginWindow" +#define PLACEHOLDER_TEXT B_UTF8_ELLIPSIS + +enum ActionTabs { + TAB_LOGIN = 0, + TAB_CREATE_ACCOUNT = 1 +}; enum { MSG_SEND = 'send', @@ -41,6 +52,26 @@ enum { MSG_VALIDATE_FIELDS = 'vldt' }; +/*! The creation of an account requires that some prerequisite data is first + loaded in or may later need to be refreshed. This enum controls what + elements of the setup should be performed. +*/ + +enum CreateAccountSetupMask { + CREATE_CAPTCHA = 1 << 1, + FETCH_USER_USAGE_CONDITIONS = 1 << 2 +}; + +/*! A background thread runs to gather data to use in the interface for creating + a new user. This structure is passed to the background thread. +*/ + +struct CreateAccountSetupThreadData { + UserLoginWindow* window; + uint32 mask; + // defines what setup steps are required +}; + UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model) : @@ -51,6 +82,7 @@ UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model) fPreferredLanguageCode(LANGUAGE_DEFAULT_CODE), fModel(model), fMode(NONE), + fUserUsageConditions(NULL), fWorkerThread(-1) { AddToSubset(parent); @@ -90,6 +122,19 @@ UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model) fEmailField = new BTextControl(B_TRANSLATE("Email address:"), "", NULL); fCaptchaView = new BitmapView("captcha view"); fCaptchaResultField = new BTextControl("", "", NULL); + fConfirmMinimumAgeCheckBox = new BCheckBox("confirm minimum age", + PLACEHOLDER_TEXT, + // is filled in when the user usage conditions data is available + NULL); + fConfirmMinimumAgeCheckBox->SetEnabled(false); + fConfirmUserUsageConditionsCheckBox = new BCheckBox( + "confirm user usage conditions", + B_TRANSLATE("I agree to the usage conditions for users"), + NULL); + fUserUsageConditionsLink = new LinkView("user usage conditions view", + B_TRANSLATE("View the usage conditions for users"), + new BMessage(MSG_VIEW_LATEST_USER_USAGE_CONDITIONS)); + fUserUsageConditionsLink->SetTarget(this); // Setup modification messages on all text fields to trigger validation // of input @@ -103,7 +148,6 @@ UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model) new BMessage(MSG_VALIDATE_FIELDS)); fCaptchaResultField->SetModificationMessage( new BMessage(MSG_VALIDATE_FIELDS)); - fTabView = new TabView(BMessenger(this), BMessage(MSG_TAB_SELECTED)); @@ -126,7 +170,9 @@ UserLoginWindow::UserLoginWindow(BWindow* parent, BRect frame, Model& model) .AddMenuField(fLanguageCodeField, 0, 4) .Add(fCaptchaView, 0, 5) .Add(fCaptchaResultField, 1, 5) - + .Add(fConfirmMinimumAgeCheckBox, 1, 6) + .Add(fConfirmUserUsageConditionsCheckBox, 1, 7) + .Add(fUserUsageConditionsLink, 1, 8) .SetInsets(B_USE_DEFAULT_SPACING) ; fTabView->AddTab(createAccountCard); @@ -172,6 +218,10 @@ UserLoginWindow::MessageReceived(BMessage* message) _ValidateCreateAccountFields(); break; + case MSG_VIEW_LATEST_USER_USAGE_CONDITIONS: + _ViewUserUsageConditions(); + break; + case MSG_SEND: switch (fMode) { case LOGIN: @@ -190,10 +240,10 @@ UserLoginWindow::MessageReceived(BMessage* message) int32 tabIndex; if (message->FindInt32("tab index", &tabIndex) == B_OK) { switch (tabIndex) { - case 0: + case TAB_LOGIN: _SetMode(LOGIN); break; - case 1: + case TAB_CREATE_ACCOUNT: _SetMode(CREATE_ACCOUNT); break; default: @@ -212,6 +262,10 @@ UserLoginWindow::MessageReceived(BMessage* message) fCaptchaResultField->SetText(""); break; + case MSG_USER_USAGE_CONDITIONS_DATA: + _SetUserUsageConditions(new UserUsageConditions(message)); + break; + case MSG_LANGUAGE_SELECTED: message->FindString("code", &fPreferredLanguageCode); break; @@ -242,15 +296,14 @@ UserLoginWindow::_SetMode(Mode mode) switch (fMode) { case LOGIN: - fTabView->Select((int32)0); + fTabView->Select(TAB_LOGIN); fSendButton->SetLabel(B_TRANSLATE("Log in")); fUsernameField->MakeFocus(); break; case CREATE_ACCOUNT: - fTabView->Select(1); + fTabView->Select(TAB_CREATE_ACCOUNT); fSendButton->SetLabel(B_TRANSLATE("Create account")); - if (fCaptchaToken.IsEmpty()) - _RequestCaptcha(); + _CreateAccountSetupIfNecessary(); fNewUsernameField->MakeFocus(); _ValidateCreateAccountFields(); break; @@ -296,6 +349,9 @@ UserLoginWindow::_ValidateCreateAccountFields(bool alertProblems) BString password2(fRepeatPasswordField->Text()); BString email(fEmailField->Text()); BString captcha(fCaptchaResultField->Text()); + bool minimumAgeConfirmed = fConfirmMinimumAgeCheckBox->Value() != 0; + bool userUsageConditionsConfirmed = + fConfirmUserUsageConditionsCheckBox->Value() != 0; // TODO: Use the same validation as the web-serivce bool validUserName = nickName.Length() >= 3; @@ -356,6 +412,16 @@ UserLoginWindow::_ValidateCreateAccountFields(bool alertProblems) "The captcha puzzle needs to be solved.") << "\n\n"; } + if (!minimumAgeConfirmed) { + message << B_TRANSLATE( + "The minimum age requirements must be met.") << "\n\n"; + } + + if (!userUsageConditionsConfirmed) { + message << B_TRANSLATE( + "The usage conditions for users must be agreed to.") << "\n\n"; + } + BAlert* alert = new(std::nothrow) BAlert( B_TRANSLATE("Input validation"), message, @@ -407,24 +473,57 @@ UserLoginWindow::_CreateAccount() void -UserLoginWindow::_RequestCaptcha() +UserLoginWindow::_CreateAccountSetupIfNecessary() { - if (Lock()) { - fCaptchaToken = ""; - fCaptchaView->UnsetBitmap(); - fCaptchaImage.Unset(); - Unlock(); - } + uint32 setupMask = 0; + if (fCaptchaToken.IsEmpty()) + setupMask |= CREATE_CAPTCHA; + if (fUserUsageConditions == NULL) + setupMask |= FETCH_USER_USAGE_CONDITIONS; + _CreateAccountSetup(setupMask); +} + + +void +UserLoginWindow::_CreateAccountSetup(uint32 mask) +{ + if (mask == 0) + return; BAutolock locker(&fLock); if (fWorkerThread >= 0) return; - thread_id thread = spawn_thread(&_RequestCaptchaThreadEntry, - "Captcha requester", B_NORMAL_PRIORITY, this); + if (!Lock()) + debugger("unable to lock the user login window"); + + if ((mask & CREATE_CAPTCHA) != 0) { + fCaptchaToken = ""; + fCaptchaView->UnsetBitmap(); + fCaptchaImage.Unset(); + } + + if ((mask & FETCH_USER_USAGE_CONDITIONS) != 0) { + fConfirmMinimumAgeCheckBox->SetLabel(PLACEHOLDER_TEXT); + fConfirmMinimumAgeCheckBox->SetValue(0); + fConfirmUserUsageConditionsCheckBox->SetValue(0); + } + + Unlock(); + + CreateAccountSetupThreadData* threadData = new CreateAccountSetupThreadData; + threadData->window = this; + threadData->mask = mask; + + thread_id thread = spawn_thread(&_CreateAccountSetupThreadEntry, + "Create account setup", B_NORMAL_PRIORITY, threadData); if (thread >= 0) _SetWorkerThread(thread); + else { + debugger("unable to start a thread to gather data for creating an " + "account"); + } } @@ -469,6 +568,9 @@ UserLoginWindow::_SetWorkerThread(thread_id thread) fEmailField->SetEnabled(enabled); fLanguageCodeField->SetEnabled(enabled); fCaptchaResultField->SetEnabled(enabled); + fConfirmMinimumAgeCheckBox->SetEnabled(enabled); + fConfirmUserUsageConditionsCheckBox->SetEnabled(enabled); + fUserUsageConditionsLink->SetEnabled(enabled); fSendButton->SetEnabled(enabled); if (thread >= 0) { @@ -482,6 +584,45 @@ UserLoginWindow::_SetWorkerThread(thread_id thread) } +void +UserLoginWindow::_CreateAccountUserUsageConditionsSetupThread() +{ + UserUsageConditions conditions; + WebAppInterface interface = fModel.GetWebAppInterface(); + + if (interface.RetrieveUserUsageConditions(NULL, conditions) == B_OK) { + BMessage dataMessage(MSG_USER_USAGE_CONDITIONS_DATA); + conditions.Archive(&dataMessage, true); + BMessenger(this).SendMessage(&dataMessage); + } else { + AppUtils::NotifySimpleError( + B_TRANSLATE("User Usage Conditions Download Problem"), + B_TRANSLATE("An error has arisen downloading the user usage " + "conditions. Check the log for details and try again.")); + BMessenger(this).SendMessage(B_QUIT_REQUESTED); + } +} + + +/*! This method is hit when the user usage conditions data arrives back from the + server. At this point some of the UI elements may need to be updated. +*/ + +void +UserLoginWindow::_SetUserUsageConditions( + UserUsageConditions* userUsageConditions) +{ + fUserUsageConditions = userUsageConditions; + BString minimumAgeString; + minimumAgeString.SetToFormat("%" B_PRId8, + fUserUsageConditions->MinimumAge()); + BString label = B_TRANSLATE( + "I am %MinimumAgeYears% years of age or older"); + label.ReplaceAll("%MinimumAgeYears%", minimumAgeString); + fConfirmMinimumAgeCheckBox->SetLabel(label); +} + + int32 UserLoginWindow::_AuthenticateThreadEntry(void* data) { @@ -549,16 +690,22 @@ UserLoginWindow::_AuthenticateThread() int32 -UserLoginWindow::_RequestCaptchaThreadEntry(void* data) +UserLoginWindow::_CreateAccountSetupThreadEntry(void* data) { - UserLoginWindow* window = reinterpret_cast(data); - window->_RequestCaptchaThread(); + CreateAccountSetupThreadData* threadData = + reinterpret_cast(data); + if ((threadData->mask & CREATE_CAPTCHA) != 0) + threadData->window->_CreateAccountCaptchaSetupThread(); + if ((threadData->mask & FETCH_USER_USAGE_CONDITIONS) != 0) + threadData->window->_CreateAccountUserUsageConditionsSetupThread(); + threadData->window->_SetWorkerThread(-1); + delete threadData; return 0; } void -UserLoginWindow::_RequestCaptchaThread() +UserLoginWindow::_CreateAccountCaptchaSetupThread() { WebAppInterface interface; BMessage info; @@ -593,8 +740,6 @@ UserLoginWindow::_RequestCaptchaThread() } else { fprintf(stderr, "Failed to obtain captcha: %s\n", strerror(status)); } - - _SetWorkerThread(-1); } @@ -613,12 +758,22 @@ UserLoginWindow::_CreateAccountThread() if (!Lock()) return; + if (fUserUsageConditions == NULL) + debugger("missing user usage conditions when creating an account"); + + if (fConfirmMinimumAgeCheckBox->Value() == 0 + || fConfirmUserUsageConditionsCheckBox->Value() == 0) { + debugger("expected that the minimum age and user usage conditions are" + "agreed to at this point"); + } + BString nickName(fNewUsernameField->Text()); BString passwordClear(fNewPasswordField->Text()); BString email(fEmailField->Text()); BString captchaToken(fCaptchaToken); BString captchaResponse(fCaptchaResultField->Text()); BString languageCode(fPreferredLanguageCode); + BString userUsageConditionsCode(fUserUsageConditions->Code()); Unlock(); @@ -627,7 +782,7 @@ UserLoginWindow::_CreateAccountThread() status_t status = interface.CreateUser( nickName, passwordClear, email, captchaToken, captchaResponse, - languageCode, info); + languageCode, userUsageConditionsCode, info); BAutolock locker(&fLock); @@ -678,7 +833,7 @@ UserLoginWindow::_CreateAccountThread() // We need a new captcha, it can be used only once fCaptchaToken = ""; - _RequestCaptcha(); + _CreateAccountSetup(CREATE_CAPTCHA); } else { fModel.SetAuthorization(nickName, passwordClear, true); @@ -739,3 +894,17 @@ UserLoginWindow::_CollectValidationFailures(const BMessage& result, error << B_TRANSLATE("But none could be listed here, sorry."); } } + + +/*! Opens a new window that shows the already downloaded user usage conditions. +*/ + +void +UserLoginWindow::_ViewUserUsageConditions() +{ + if (fUserUsageConditions == NULL) + debugger("the user usage conditions should be set"); + UserUsageConditionsWindow* window = new UserUsageConditionsWindow( + fModel, *fUserUsageConditions); + window->Show(); +} \ No newline at end of file diff --git a/src/apps/haikudepot/ui/UserLoginWindow.h b/src/apps/haikudepot/ui/UserLoginWindow.h index ee52d452ca..7cc1ee0147 100644 --- a/src/apps/haikudepot/ui/UserLoginWindow.h +++ b/src/apps/haikudepot/ui/UserLoginWindow.h @@ -14,11 +14,14 @@ class BButton; +class BCheckBox; class BMenuField; class BTabView; class BTextControl; class BitmapView; +class LinkView; class Model; +class UserUsageConditions; class UserLoginWindow : public BWindow { @@ -34,6 +37,7 @@ public: const BMessage& message); private: + enum Mode { NONE = 0, LOGIN, @@ -45,7 +49,8 @@ private: bool alertProblems = false); void _Login(); void _CreateAccount(); - void _RequestCaptcha(); + void _CreateAccountSetup(uint32 mask); + void _CreateAccountSetupIfNecessary(); void _LoginSuccessful(const BString& message); void _SetWorkerThread(thread_id thread); @@ -53,8 +58,12 @@ private: static int32 _AuthenticateThreadEntry(void* data); void _AuthenticateThread(); - static int32 _RequestCaptchaThreadEntry(void* data); - void _RequestCaptchaThread(); + static int32 _CreateAccountSetupThreadEntry(void* data); + void _CreateAccountCaptchaSetupThread(); + void _CreateAccountUserUsageConditionsSetupThread(); + + void _SetUserUsageConditions( + UserUsageConditions* userUsageConditions); static int32 _CreateAccountThreadEntry(void* data); void _CreateAccountThread(); @@ -63,6 +72,8 @@ private: const BMessage& result, BString& error) const; + void _ViewUserUsageConditions(); + private: BMessenger fOnSuccessTarget; BMessage fOnSuccessMessage; @@ -79,6 +90,9 @@ private: BMenuField* fLanguageCodeField; BitmapView* fCaptchaView; BTextControl* fCaptchaResultField; + BCheckBox* fConfirmMinimumAgeCheckBox; + BCheckBox* fConfirmUserUsageConditionsCheckBox; + LinkView* fUserUsageConditionsLink; BButton* fSendButton; BButton* fCancelButton; @@ -91,6 +105,9 @@ private: Mode fMode; + UserUsageConditions* + fUserUsageConditions; + BLocker fLock; thread_id fWorkerThread; }; diff --git a/src/apps/haikudepot/ui/UserUsageConditionsWindow.cpp b/src/apps/haikudepot/ui/UserUsageConditionsWindow.cpp index 829e08d2a2..88853da2d1 100644 --- a/src/apps/haikudepot/ui/UserUsageConditionsWindow.cpp +++ b/src/apps/haikudepot/ui/UserUsageConditionsWindow.cpp @@ -43,48 +43,117 @@ #define LINES_INTRODUCTION_TEXT 2 - -enum { - MSG_USER_USAGE_CONDITIONS_DATA = 'uucd', - MSG_USER_USAGE_CONDITIONS_ERROR = 'uuce' -}; +#define WINDOW_FRAME BRect(0, 0, 500, 400) -UserUsageConditionsWindow::UserUsageConditionsWindow(BWindow* parent, - BRect frame, Model& model, UserUsageConditionsSelectionMode mode) +UserUsageConditionsWindow::UserUsageConditionsWindow(Model& model, + UserUsageConditions& userUsageConditions) : - BWindow(frame, B_TRANSLATE("User Usage Conditions"), - B_FLOATING_WINDOW_LOOK, B_FLOATING_SUBSET_WINDOW_FEEL, + BWindow(WINDOW_FRAME, B_TRANSLATE("User Usage Conditions"), + B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, + B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS + | B_NOT_RESIZABLE | B_NOT_ZOOMABLE), + fMode(FIXED), + fModel(model), + fWorkerThread(-1) +{ + _InitUiControls(); + + BScrollView* scrollView = new BScrollView("copy scroll view", fCopyView, + 0, false, true, B_PLAIN_BORDER); + BButton* okButton = new BButton("ok", B_TRANSLATE("OK"), + new BMessage(B_QUIT_REQUESTED)); + + BLayoutBuilder::Group<>(this, B_VERTICAL) + .SetInsets(B_USE_WINDOW_INSETS) + .Add(fVersionStringView, 1) + .Add(scrollView, 97) + .Add(fAgeNoteStringView, 1) + .AddGroup(B_HORIZONTAL, 1) + .AddGlue() + .Add(okButton) + .End() + .End(); + + CenterOnScreen(); + _DisplayData(userUsageConditions); +} + +UserUsageConditionsWindow::UserUsageConditionsWindow( + Model& model, UserUsageConditionsSelectionMode mode) + : + BWindow(WINDOW_FRAME, B_TRANSLATE("User Usage Conditions"), + B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_RESIZABLE | B_NOT_ZOOMABLE), fMode(mode), fModel(model), fWorkerThread(-1) { - AddToSubset(parent); - if (mode != LATEST) debugger("only the LATEST user usage conditions are handled for now"); + _InitUiControls(); + fWorkerIndicator = new BarberPole("fetch data worker indicator"); BSize workerIndicatorSize; workerIndicatorSize.SetHeight(20); fWorkerIndicator->SetExplicitMinSize(workerIndicatorSize); - fCopyView = new MarkupTextView("copy view"); - fCopyView->SetViewUIColor(B_NO_COLOR); - fCopyView->SetLowColor(RGB_COLOR_WHITE); - fCopyView->SetInsets(8.0f); - - BScrollView* scrollView = new BScrollView("copy scroll view", fCopyView, - 0, false, true, B_PLAIN_BORDER); - BTextView* introductionTextView = new BTextView("introduction text view"); introductionTextView->AdoptSystemColors(); introductionTextView->MakeEditable(false); introductionTextView->MakeSelectable(false); introductionTextView->SetText(B_TRANSLATE(_IntroductionTextForMode(mode))); + BSize introductionSize; + introductionSize.SetHeight( + _ExpectedIntroductionTextHeight(introductionTextView)); + introductionTextView->SetExplicitPreferredSize(introductionSize); + + BScrollView* scrollView = new BScrollView("copy scroll view", fCopyView, + 0, false, true, B_PLAIN_BORDER); + BButton* okButton = new BButton("ok", B_TRANSLATE("OK"), + new BMessage(B_QUIT_REQUESTED)); + + BLayoutBuilder::Group<>(this, B_VERTICAL) + .SetInsets(B_USE_WINDOW_INSETS) + .Add(introductionTextView, 1) + .AddGlue() + .Add(fVersionStringView, 1) + .Add(scrollView, 95) + .Add(fAgeNoteStringView, 1) + .AddGroup(B_HORIZONTAL, 1) + .AddGlue() + .Add(okButton) + .End() + .Add(fWorkerIndicator, 1) + .End(); + + CenterOnScreen(); + + _FetchData(); + // start a new thread to pull down the user usage conditions data. +} + + +UserUsageConditionsWindow::~UserUsageConditionsWindow() +{ +} + + +/*! This sets up the UI controls / interface elements that are not specific to + a given mode of viewing. +*/ + +void +UserUsageConditionsWindow::_InitUiControls() +{ + fCopyView = new MarkupTextView("copy view"); + fCopyView->SetViewUIColor(B_NO_COLOR); + fCopyView->SetLowColor(RGB_COLOR_WHITE); + fCopyView->SetInsets(8.0f); + fAgeNoteStringView = new BStringView("age note string view", PLACEHOLDER_TEXT); fAgeNoteStringView->AdoptSystemColors(); @@ -102,38 +171,6 @@ UserUsageConditionsWindow::UserUsageConditionsWindow(BWindow* parent, fVersionStringView->SetHighUIColor(B_PANEL_TEXT_COLOR, B_DARKEN_3_TINT); fVersionStringView->SetExplicitMaxSize( BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET)); - - BSize introductionSize; - introductionSize.SetHeight( - _ExpectedIntroductionTextHeight(introductionTextView)); - introductionTextView->SetExplicitPreferredSize(introductionSize); - - BButton* okButton = new BButton("ok", B_TRANSLATE("OK"), - new BMessage(B_QUIT_REQUESTED)); - - BLayoutBuilder::Group<>(this, B_VERTICAL) - .SetInsets(B_USE_WINDOW_INSETS) - .Add(introductionTextView, 1) - .AddGlue() - .Add(fVersionStringView, 1) - .Add(scrollView, 96) - .Add(fAgeNoteStringView, 1) - .AddGroup(B_HORIZONTAL, 1) - .AddGlue() - .Add(okButton) - .End() - .Add(fWorkerIndicator, 1) - .End(); - - CenterIn(parent->Frame()); - - _FetchData(); - // start a new thread to pull down the user usage conditions data. -} - - -UserUsageConditionsWindow::~UserUsageConditionsWindow() -{ } diff --git a/src/apps/haikudepot/ui/UserUsageConditionsWindow.h b/src/apps/haikudepot/ui/UserUsageConditionsWindow.h index 07c4fdcaff..6e8facc0e9 100644 --- a/src/apps/haikudepot/ui/UserUsageConditionsWindow.h +++ b/src/apps/haikudepot/ui/UserUsageConditionsWindow.h @@ -22,14 +22,17 @@ class Model; enum UserUsageConditionsSelectionMode { LATEST = 1, - USER = 2 + USER = 2, + FIXED = 3 + // means that the user usage conditions are supplied to the window. }; class UserUsageConditionsWindow : public BWindow { public: - UserUsageConditionsWindow(BWindow* parent, - BRect frame, Model& model, + UserUsageConditionsWindow(Model& model, + UserUsageConditions& userUsageConditions); + UserUsageConditionsWindow(Model& model, UserUsageConditionsSelectionMode mode); virtual ~UserUsageConditionsWindow(); @@ -37,6 +40,8 @@ public: virtual bool QuitRequested(); private: + void _InitUiControls(); + static const BString _VersionText(const BString& code); static const BString _MinimumAgeText(uint8 minimumAge); static const BString _IntroductionTextForMode(