/* * Copyright 2008, François Revol, . All rights reserved. * Distributed under the terms of the MIT License. */ #include #include #include #include #ifdef __HAIKU__ #include #endif #include #include "LoginApp.h" #include "LoginView.h" #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "Login View" #define LW 120 #define CSEP 15 #define BH 20 #define BW 60 class PwdItem : public BStringItem { public: PwdItem(struct passwd *pwd, uint32 level = 0, bool expanded = true) : BStringItem("", level, expanded) { if (pwd) { BString name(pwd->pw_gecos); // TODO: truncate at first ; fLogin = pwd->pw_name; SetText(name.String()); } }; virtual ~PwdItem() {}; const char* Login() const { return fLogin.String(); }; private: BString fLogin; }; LoginView::LoginView(BRect frame) : BView(frame, "LoginView", B_FOLLOW_ALL, B_PULSE_NEEDED) { // TODO: when I don't need to test in BeOS anymore, // rewrite to use layout engine. SetViewUIColor(B_PANEL_BACKGROUND_COLOR); SetLowUIColor(ViewUIColor()); BRect r; r.Set(CSEP, CSEP, LW, Bounds().Height() - 3 * CSEP - BH); fUserList = new BListView(r, "users"); BScrollView *sv = new BScrollView("userssv", fUserList, B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true); AddChild(sv); fUserList->SetSelectionMessage(new BMessage(kUserSelected)); fUserList->SetInvocationMessage(new BMessage(kUserInvoked)); r.Set(LW + 30, Bounds().top + CSEP, Bounds().right - CSEP, Bounds().top + CSEP + CSEP); fLoginControl = new BTextControl(r, "login", B_TRANSLATE("Login:"), "", new BMessage(kLoginEdited)); AddChild(fLoginControl); r.OffsetBySelf(0, CSEP + CSEP); fPasswordControl = new BTextControl(r, "password", B_TRANSLATE("Password:"), "", new BMessage(kPasswordEdited)); fPasswordControl->TextView()->HideTyping(true); AddChild(fPasswordControl); r.OffsetBySelf(0, CSEP + CSEP); fHidePasswordCheckBox = new BCheckBox(r, "hidepw", B_TRANSLATE("Hide password"), new BMessage(kHidePassword)); fHidePasswordCheckBox->SetValue(1); AddChild(fHidePasswordCheckBox); // buttons float buttonWidth = BW; //(Bounds().Width() - 4 * CSEP) / 3; BRect buttonRect(0, Bounds().bottom - BH, buttonWidth, Bounds().bottom); buttonRect.OffsetBySelf(CSEP, -CSEP); fHaltButton = new BButton(buttonRect, "halt", B_TRANSLATE("Halt"), new BMessage(kHaltAction)); fHaltButton->ResizeToPreferred(); AddChild(fHaltButton); buttonRect.OffsetBySelf(CSEP + fHaltButton->Frame().Width(), 0); fRebootButton = new BButton(buttonRect, "reboot", B_TRANSLATE("Reboot"), new BMessage(kRebootAction)); fRebootButton->ResizeToPreferred(); AddChild(fRebootButton); BRect infoRect(buttonRect); infoRect.OffsetBySelf(fRebootButton->Frame().Width() + CSEP, 0); buttonRect.OffsetToSelf(Bounds().Width() - CSEP - buttonWidth, Bounds().Height() - CSEP - BH); fLoginButton = new BButton(buttonRect, "ok", B_TRANSLATE("OK"), new BMessage(kAttemptLogin)); fLoginButton->ResizeToPreferred(); AddChild(fLoginButton); infoRect.right = buttonRect.left - CSEP + 5; BString info; //info << hostname; fInfoView = new BStringView(infoRect, "info", info.String()); AddChild(fInfoView); } LoginView::~LoginView() { } void LoginView::AttachedToWindow() { fUserList->SetTarget(this); fLoginControl->SetTarget(this); fPasswordControl->SetTarget(this); fHidePasswordCheckBox->SetTarget(this); fHaltButton->SetTarget(be_app_messenger); fRebootButton->SetTarget(be_app_messenger); fLoginButton->SetTarget(this); Window()->SetDefaultButton(fLoginButton); //fLoginControl->MakeFocus(); fUserList->MakeFocus(); // populate user list BMessenger(this).SendMessage(kAddNextUser); // size window relative to buttons BRect bounds = Window()->Bounds(); float spacing = fHaltButton->Frame().left; bounds.bottom = fLoginButton->Frame().bottom + spacing; bounds.right = fLoginButton->Frame().right + spacing; Window()->ResizeTo(bounds.Width(), bounds.Height()); // Center info view BPoint leftTop = fInfoView->Frame().LeftTop(); leftTop.y += fHaltButton->Frame().Height() / 2; leftTop.y -= fInfoView->Bounds().Height() / 2; fInfoView->MoveTo(leftTop); } void LoginView::MessageReceived(BMessage *message) { switch (message->what) { case kSetProgress: break; case kAddNextUser: AddNextUser(); break; case kUserSelected: { int32 selection = fUserList->CurrentSelection(); if (selection > -1) { PwdItem *item = dynamic_cast( fUserList->ItemAt(selection)); if (item) fLoginControl->SetText(item->Login()); } break; } case kUserInvoked: fPasswordControl->MakeFocus(); break; case kLoginEdited: break; case kHidePassword: fPasswordControl->TextView()->HideTyping( fHidePasswordCheckBox->Value()); break; case kAttemptLogin: { // if no pass specified and we were selecting the user, // give a chance to enter the password // else we might want to enter an empty password. if (strlen(fPasswordControl->Text()) < 1 && (fUserList->IsFocus() || fLoginControl->IsFocus())) { fPasswordControl->MakeFocus(); break; } BMessage *m = new BMessage(kAttemptLogin); m->AddString("login", fLoginControl->Text()); m->AddString("password", fPasswordControl->Text()); be_app->PostMessage(m, NULL, this); break; } case kLoginBad: fPasswordControl->SetText(""); EnableControls(false); fInfoView->SetText(B_TRANSLATE("Invalid login!")); if (Window()) { BPoint savedPos = Window()->Frame().LeftTop(); for (int i = 0; i < 10; i++) { BPoint p(savedPos); p.x += (i%2) ? 10 : -10; Window()->MoveTo(p); Window()->UpdateIfNeeded(); snooze(30000); } Window()->MoveTo(savedPos); } EnableControls(true); break; case kLoginOk: // XXX: quit ? if (Window()) { Window()->Hide(); } break; default: message->PrintToStream(); BView::MessageReceived(message); } } void LoginView::Pulse() { BString info; time_t now = time(NULL); struct tm *t = localtime(&now); // TODO: use strftime and locale settings info << asctime(t); info.RemoveSet("\r\n"); fInfoView->SetText(info.String()); } void LoginView::AddNextUser() { struct passwd *pwd; if (fUserList->CountItems() < 1) setpwent(); pwd = getpwent(); if (pwd && pwd->pw_shell && strcmp(pwd->pw_shell, "false") && strcmp(pwd->pw_shell, "true") && strcmp(pwd->pw_shell, "/bin/false") && strcmp(pwd->pw_shell, "/bin/true")) { // not disabled PwdItem *item = new PwdItem(pwd); fUserList->AddItem(item); } if (pwd) BMessenger(this).SendMessage(kAddNextUser); else endpwent(); } void LoginView::EnableControls(bool enable) { int32 i; for (i = 0; i < fUserList->CountItems(); i++) { fUserList->ItemAt(i)->SetEnabled(enable); } fLoginControl->SetEnabled(enable); fPasswordControl->SetEnabled(enable); fHidePasswordCheckBox->SetEnabled(enable); fHaltButton->SetEnabled(enable); fRebootButton->SetEnabled(enable); fLoginButton->SetEnabled(enable); }