1/*
2 * Copyright 2003-2010 Haiku Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		J��r��me Duval
7 */
8
9
10#include "PasswordAlert.h"
11
12#include <string.h>
13
14#include <File.h>
15#include <FindDirectory.h>
16#include <IconUtils.h>
17#include <Path.h>
18#include <Resources.h>
19#include <Screen.h>
20#include <View.h>
21
22
23static const int kWindowIconOffset = 27;
24static const int kIconStripeWidth = 30;
25static const int kTextIconOffset = kWindowIconOffset + kIconStripeWidth - 2;
26static const int kTextTopOffset = 6;
27static const int kSemTimeOut = 50000;
28
29
30class TAlertView : public BView {
31public:
32							TAlertView(BRect frame);
33							TAlertView(BMessage* archive);
34							~TAlertView();
35
36	virtual void			Draw(BRect updateRect);
37
38			void			SetBitmap(BBitmap* Icon)	{ fIconBitmap = Icon; }
39			BBitmap*		Bitmap()					{ return fIconBitmap; }
40
41private:
42		BBitmap*			fIconBitmap;
43};
44
45
46PasswordAlert::PasswordAlert(const char* title, const char* text)
47	:
48	BWindow(BRect(0, 0, 450, 45), title, B_MODAL_WINDOW, B_NOT_CLOSABLE | B_NOT_RESIZABLE),
49	fTextControl(NULL),
50	fAlertSem(-1)
51{
52	// Set up the "_master_" view
53	TAlertView* masterView = new TAlertView(Bounds());
54	masterView->SetBitmap(InitIcon());
55	AddChild(masterView);
56
57	// Set up the text view
58	BRect textControlRect(kTextIconOffset, kTextTopOffset,
59		Bounds().right - 5, Bounds().bottom);
60
61	fTextControl = new BTextControl(textControlRect, "_password_", text, NULL, new BMessage('pass'),
62		B_FOLLOW_ALL);
63	fTextControl->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
64	fTextControl->TextView()->HideTyping(true);
65	fTextControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
66	fTextControl->SetDivider(10 + fTextControl->StringWidth(text));
67
68	masterView->AddChild(fTextControl);
69
70	BRect screenFrame = BScreen(B_MAIN_SCREEN_ID).Frame();
71	BPoint pt;
72	pt.x = screenFrame.Width() / 2 - Bounds().Width() / 2;
73	pt.y = screenFrame.Height() / 2 - Bounds().Height() / 2;
74
75	if (screenFrame.Contains(pt))
76		MoveTo(pt);
77
78	fTextControl->MakeFocus();
79}
80
81
82PasswordAlert::~PasswordAlert()
83{
84}
85
86
87BBitmap*
88PasswordAlert::InitIcon()
89{
90	// The alert icons are in the app_server resources
91	BBitmap* icon = NULL;
92	BPath path;
93	if (find_directory(B_BEOS_SERVERS_DIRECTORY, &path) == B_OK) {
94		path.Append("app_server");
95		BFile file;
96		if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK) {
97			BResources resources;
98			if (resources.SetTo(&file) == B_OK) {
99				// Which icon are we trying to load?
100				const char* iconName = "warn";
101
102				// Load the raw icon data
103				size_t size;
104				const void* rawIcon =
105					resources.LoadResource(B_VECTOR_ICON_TYPE, iconName, &size);
106
107				if (rawIcon != NULL) {
108					// Now build the bitmap
109					icon = new BBitmap(BRect(0, 0, 31, 31), B_RGBA32);
110					if (BIconUtils::GetVectorIcon((const uint8*)rawIcon, size,
111							icon) != B_OK) {
112						delete icon;
113						return NULL;
114					}
115				}
116			}
117		}
118	}
119
120	return icon;
121}
122
123
124void
125PasswordAlert::Go(BString &password)
126{
127	fAlertSem = create_sem(0, "AlertSem");
128	if (fAlertSem < B_OK) {
129		Quit();
130		return;
131	}
132
133	// Get the originating window, if it exists
134	BWindow* window =
135		dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL)));
136
137	Show();
138
139	// Heavily modified from TextEntryAlert code; the original didn't let the
140	// blocked window ever draw.
141	if (window) {
142		status_t err;
143		for (;;) {
144			do {
145				err = acquire_sem_etc(fAlertSem, 1, B_RELATIVE_TIMEOUT,
146									  kSemTimeOut);
147				// We've (probably) had our time slice taken away from us
148			} while (err == B_INTERRUPTED);
149
150			if (err == B_BAD_SEM_ID) {
151				// Semaphore was finally nuked in MessageReceived
152				break;
153			}
154			window->UpdateIfNeeded();
155		}
156	} else {
157		// No window to update, so just hang out until we're done.
158		while (acquire_sem(fAlertSem) == B_INTERRUPTED) {
159		}
160	}
161
162	// Have to cache the value since we delete on Quit()
163	password = fTextControl->Text();
164	if (Lock())
165		Quit();
166}
167
168
169void
170PasswordAlert::MessageReceived(BMessage* msg)
171{
172	if (msg->what != 'pass')
173		return BWindow::MessageReceived(msg);
174
175	delete_sem(fAlertSem);
176	fAlertSem = -1;
177}
178
179
180//	#pragma mark - TAlertView
181
182
183TAlertView::TAlertView(BRect frame)
184	:
185	BView(frame, "TAlertView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW),
186	fIconBitmap(NULL)
187{
188	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
189}
190
191
192TAlertView::~TAlertView()
193{
194	delete fIconBitmap;
195}
196
197
198void
199TAlertView::Draw(BRect updateRect)
200{
201	// Here's the fun stuff
202	if (fIconBitmap) {
203		BRect stripeRect = Bounds();
204		stripeRect.right = kIconStripeWidth;
205		SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
206		FillRect(stripeRect);
207
208		SetDrawingMode(B_OP_ALPHA);
209		DrawBitmapAsync(fIconBitmap, BPoint(18, 6));
210		SetDrawingMode(B_OP_COPY);
211	}
212}
213