1// AuthenticationPanel.cpp
2
3#include <stdio.h>
4
5#include <Screen.h>
6
7#include <Box.h>
8#include <Button.h>
9#include <CheckBox.h>
10#include <Message.h>
11#include <String.h>
12#include <StringView.h>
13#include <TextControl.h>
14
15#include "AuthenticationPanel.h"
16
17enum {
18	MSG_PANEL_OK,
19	MSG_PANEL_CANCEL,
20};
21
22// constructor
23AuthenticationPanel::AuthenticationPanel(BRect frame)
24	: Panel(frame, "Name Panel",
25			B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
26			B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE | B_NOT_ZOOMABLE),
27	  fCancelled(false),
28	  fExitSem(B_ERROR)
29{
30	fExitSem = create_sem(0, "Authentication Panel");
31
32	BRect controlFrame(0.0, 0.0, frame.Width(), 15.0);
33
34	fNameTC = new BTextControl(controlFrame, "name", "Username", "", NULL,
35							   B_FOLLOW_LEFT | B_FOLLOW_RIGHT);
36
37	fPassTC = new BTextControl(controlFrame, "pass", "Password", "", NULL,
38							   B_FOLLOW_LEFT | B_FOLLOW_RIGHT);
39
40	fKeepUsingCB = new BCheckBox(controlFrame, "again",
41								 "Use login for all shares of this host",
42								 NULL, B_FOLLOW_LEFT | B_FOLLOW_RIGHT);
43
44	BRect buttonFrame(0.0, 0.0, 20.0, 15.0);
45	fOkB = new BButton(buttonFrame, "ok", "OK",
46					   new BMessage(MSG_PANEL_OK));
47	fCancelB = new BButton(buttonFrame, "cancel", "Cancel",
48						   new BMessage(MSG_PANEL_CANCEL));
49
50}
51
52// destructor
53AuthenticationPanel::~AuthenticationPanel()
54{
55	delete_sem(fExitSem);
56}
57
58// QuitRequested
59bool
60AuthenticationPanel::QuitRequested()
61{
62	fCancelled = true;
63	release_sem(fExitSem);
64	return false;
65}
66
67// MessageReceived
68void
69AuthenticationPanel::MessageReceived(BMessage* message)
70{
71	switch (message->what) {
72		case MSG_PANEL_CANCEL:
73			Cancel();
74			break;
75		case MSG_PANEL_OK: {
76			release_sem(fExitSem);
77			break;
78		}
79		default:
80			Panel::MessageReceived(message);
81	}
82}
83
84// GetAuthentication
85bool
86AuthenticationPanel::GetAuthentication(const char* server,
87									   const char* share,
88									   const char* previousUser,
89									   const char* previousPass,
90									   bool previousKeep,
91									   bool badPassword,
92									   char* user, char* pass, bool* keep)
93{
94	// configure panel and layout controls
95	BString helper("Enter login for: ");
96	helper << (server ? server : "<unkown host>") << "/";
97	helper << (share ? share : "<unkown share>");
98
99	// ignore the previous password, if it didn't work
100	if (badPassword)
101		previousPass = NULL;
102
103	SetTitle(helper.String());
104
105	BPoint offset(0.0, 5.0);
106
107	fNameTC->SetText(previousUser ? previousUser : "");
108	fNameTC->ResizeToPreferred();
109	fNameTC->MoveTo(BPoint(10.0, 10.0));
110
111	fPassTC->SetText(previousPass ? previousPass : "");
112	fPassTC->ResizeToPreferred();
113	fPassTC->MoveTo(fNameTC->Frame().LeftBottom() + offset);
114
115	fKeepUsingCB->SetValue(previousKeep);
116	fKeepUsingCB->ResizeToPreferred();
117	fKeepUsingCB->MoveTo(fPassTC->Frame().LeftBottom() + offset);
118
119	fCancelB->ResizeToPreferred();
120
121	fOkB->ResizeToPreferred();
122	fOkB->MoveTo(fKeepUsingCB->Frame().RightBottom() + offset + offset - fOkB->Frame().RightTop());
123
124	fCancelB->MoveTo(fOkB->Frame().LeftTop() - BPoint(10.0, 0.0) - fCancelB->Frame().RightTop());
125
126	BRect frame(fNameTC->Frame().LeftTop(), fOkB->Frame().RightBottom());
127
128	// work arround buggy BTextControl resizing
129	BRect nameFrame = fNameTC->Frame();
130	BRect passFrame = fPassTC->Frame();
131
132	nameFrame.right = nameFrame.left + frame.Width();
133	passFrame.right = passFrame.left + frame.Width();
134
135	float divider = fNameTC->Divider();
136
137	if (fPassTC->Divider() > divider)
138		divider = fPassTC->Divider();
139
140	delete fNameTC;
141	fNameTC = new BTextControl(nameFrame, "name", "Username", "", NULL,
142							   B_FOLLOW_LEFT | B_FOLLOW_RIGHT);
143	fNameTC->SetText(previousUser ? previousUser : "");
144
145	delete fPassTC;
146	fPassTC = new BTextControl(passFrame, "pass", "Password", "", NULL,
147							   B_FOLLOW_LEFT | B_FOLLOW_RIGHT);
148
149	fPassTC->TextView()->HideTyping(true);
150	fPassTC->SetText(previousPass ? previousPass : "");
151
152	fNameTC->SetDivider(divider);
153	fPassTC->SetDivider(divider);
154
155
156	// create background view
157	frame.InsetBy(-10.0, -10.0);
158
159	BBox* bg = new BBox(frame, "bg", B_FOLLOW_ALL,
160						B_FRAME_EVENTS | B_WILL_DRAW | B_NAVIGABLE_JUMP,
161						B_PLAIN_BORDER);
162
163	bg->AddChild(fNameTC);
164	bg->AddChild(fPassTC);
165	bg->AddChild(fKeepUsingCB);
166
167	bg->AddChild(fOkB);
168	bg->AddChild(fCancelB);
169
170	frame.OffsetTo(-10000.0, -10000.0);
171	frame = _CalculateFrame(frame);
172	MoveTo(frame.LeftTop());
173	ResizeTo(frame.Width(), frame.Height());
174
175	AddChild(bg);
176	SetDefaultButton(fOkB);
177	fNameTC->MakeFocus(true);
178
179	// start window thread
180	Show();
181
182	// let the window jitter, if the previous password was invalid
183	if (badPassword) {
184		BPoint leftTop = Frame().LeftTop();
185		const float jitterOffsets[] = { -10, 0, 10, 0 };
186		const int32 jitterOffsetCount = sizeof(jitterOffsets) / sizeof(float);
187		for (int32 i = 0; i < 30; i++) {
188			float offset = jitterOffsets[i % jitterOffsetCount];
189			MoveTo(leftTop.x + offset, leftTop.y);
190			snooze(10000);
191		}
192		MoveTo(leftTop);
193	}
194
195	// block calling thread
196	acquire_sem(fExitSem);
197
198	// window wants to quit
199	Lock();
200
201	strcpy(user, fNameTC->Text());
202	strcpy(pass, fPassTC->Text());
203	*keep = fKeepUsingCB->Value() == B_CONTROL_ON;
204
205	Quit();
206	return fCancelled;
207}
208
209// Cancel
210void
211AuthenticationPanel::Cancel()
212{
213	fCancelled = true;
214//	release_sem(fExitSem);
215
216	Panel::Cancel();
217}
218
219
220// _CalculateFrame
221BRect
222AuthenticationPanel::_CalculateFrame(BRect frame)
223{
224	BScreen screen(B_MAIN_SCREEN_ID);
225	BRect screenFrame = screen.Frame();
226	if (!screenFrame.Contains(frame)) {
227		float width = frame.Width();
228		float height = frame.Height();
229		BPoint center;
230		center.x = screenFrame.left + screenFrame.Width() / 2.0;
231		center.y = screenFrame.top + screenFrame.Height() / 4.0;
232		frame.left = center.x - width / 2.0;
233		frame.right = frame.left + width;
234		frame.top = center.y - height / 2.0;
235		frame.bottom = frame.top + height;
236	}
237	return frame;
238}
239