279 lines
7.0 KiB
C++
279 lines
7.0 KiB
C++
/*
|
|
* Copyright 2008, François Revol, <revol@free.fr>. All rights reserved.
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
#include <Catalog.h>
|
|
#include <ScrollView.h>
|
|
#include <String.h>
|
|
#include <Window.h>
|
|
#ifdef __HAIKU__
|
|
#include <Layout.h>
|
|
#endif
|
|
|
|
#include <pwd.h>
|
|
|
|
#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<PwdItem *>(
|
|
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);
|
|
}
|
|
|