2 * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
4 * All rights reserved. Distributed under the terms of the MIT License.
6 #include "AuthenticationPanel.h"
11 #include <ControlLook.h>
12 #include <GridLayoutBuilder.h>
13 #include <GroupLayoutBuilder.h>
17 #include <SeparatorView.h>
18 #include <SpaceLayoutItem.h>
19 #include <StringView.h>
20 #include <TextControl.h>
23 static const uint32 kMsgPanelOK
= 'pnok';
24 static const uint32 kMsgJitter
= 'jitr';
25 static const uint32 kHidePassword
= 'hdpw';
28 #undef B_TRANSLATION_CONTEXT
29 #define B_TRANSLATION_CONTEXT "Authentication Panel"
31 AuthenticationPanel::AuthenticationPanel(BRect parentFrame
)
33 BWindow(BRect(-1000, -1000, -900, -900),
34 B_TRANSLATE("Authentication required"), B_TITLED_WINDOW_LOOK
,
35 B_MODAL_APP_WINDOW_FEEL
, B_ASYNCHRONOUS_CONTROLS
| B_NOT_RESIZABLE
36 | B_NOT_ZOOMABLE
| B_CLOSE_ON_ESCAPE
| B_AUTO_UPDATE_SIZE_LIMITS
),
37 m_parentWindowFrame(parentFrame
),
38 m_usernameTextControl(new BTextControl("user", B_TRANSLATE("Username:"),
40 m_passwordTextControl(new BTextControl("pass", B_TRANSLATE("Password:"),
42 m_hidePasswordCheckBox(new BCheckBox("hide", B_TRANSLATE("Hide password "
43 "text"), new BMessage(kHidePassword
))),
44 m_rememberCredentialsCheckBox(new BCheckBox("remember",
45 B_TRANSLATE("Remember username and password for this site"), NULL
)),
46 m_okButton(new BButton("ok", B_TRANSLATE("OK"),
47 new BMessage(kMsgPanelOK
))),
48 m_cancelButton(new BButton("cancel", B_TRANSLATE("Cancel"),
49 new BMessage(B_QUIT_REQUESTED
))),
51 m_exitSemaphore(create_sem(0, "Authentication Panel"))
56 AuthenticationPanel::~AuthenticationPanel()
58 delete_sem(m_exitSemaphore
);
63 AuthenticationPanel::QuitRequested()
66 release_sem(m_exitSemaphore
);
72 AuthenticationPanel::MessageReceived(BMessage
* message
)
74 switch (message
->what
) {
76 release_sem(m_exitSemaphore
);
79 // TODO: Toggling this is broken in BTextView. Workaround is to
80 // set the text and selection again.
81 BString text
= m_passwordTextControl
->Text();
84 m_passwordTextControl
->TextView()->GetSelection(&selectionStart
,
86 m_passwordTextControl
->TextView()->HideTyping(
87 m_hidePasswordCheckBox
->Value() == B_CONTROL_ON
);
88 m_passwordTextControl
->SetText(text
.String());
89 m_passwordTextControl
->TextView()->Select(selectionStart
,
95 BPoint leftTop
= Frame().LeftTop();
96 const float jitterOffsets
[] = { -10, 0, 10, 0 };
97 const int32 jitterOffsetCount
= sizeof(jitterOffsets
) / sizeof(float);
98 for (int32 i
= 0; i
< 20; i
++) {
99 float offset
= jitterOffsets
[i
% jitterOffsetCount
];
100 MoveTo(leftTop
.x
+ offset
, leftTop
.y
);
107 BWindow::MessageReceived(message
);
112 bool AuthenticationPanel::getAuthentication(const BString
& text
,
113 const BString
& previousUser
, const BString
& previousPass
,
114 bool previousRememberCredentials
, bool badPassword
,
115 BString
& user
, BString
& pass
, bool* rememberCredentials
)
117 // Configure panel and layout controls.
118 rgb_color infoColor
= ui_color(B_PANEL_TEXT_COLOR
);
119 BRect
textBounds(0, 0, 250, 200);
120 BTextView
* textView
= new BTextView(textBounds
, "text", textBounds
,
121 be_plain_font
, &infoColor
, B_FOLLOW_NONE
, B_WILL_DRAW
122 | B_SUPPORTS_LAYOUT
);
123 textView
->SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
124 textView
->SetText(text
.String());
125 textView
->MakeEditable(false);
126 textView
->MakeSelectable(false);
128 m_usernameTextControl
->SetText(previousUser
.String());
129 m_passwordTextControl
->TextView()->HideTyping(true);
130 // Ignore the previous password, if it didn't work.
132 m_passwordTextControl
->SetText(previousPass
.String());
133 m_hidePasswordCheckBox
->SetValue(B_CONTROL_ON
);
134 m_rememberCredentialsCheckBox
->SetValue(previousRememberCredentials
);
137 SetLayout(new BGroupLayout(B_VERTICAL
, 0.0));
138 float spacing
= be_control_look
->DefaultItemSpacing();
139 AddChild(BGroupLayoutBuilder(B_VERTICAL
, 0.0)
140 .Add(BGridLayoutBuilder(0, spacing
)
141 .Add(textView
, 0, 0, 2)
142 .Add(m_usernameTextControl
->CreateLabelLayoutItem(), 0, 1)
143 .Add(m_usernameTextControl
->CreateTextViewLayoutItem(), 1, 1)
144 .Add(m_passwordTextControl
->CreateLabelLayoutItem(), 0, 2)
145 .Add(m_passwordTextControl
->CreateTextViewLayoutItem(), 1, 2)
146 .Add(BSpaceLayoutItem::CreateGlue(), 0, 3)
147 .Add(m_hidePasswordCheckBox
, 1, 3)
148 .Add(m_rememberCredentialsCheckBox
, 0, 4, 2)
149 .SetInsets(spacing
, spacing
, spacing
, spacing
)
151 .Add(new BSeparatorView(B_HORIZONTAL
, B_PLAIN_BORDER
))
152 .Add(BGroupLayoutBuilder(B_HORIZONTAL
, spacing
)
156 .SetInsets(spacing
, spacing
, spacing
, spacing
)
160 float textHeight
= textView
->LineHeight(0) * textView
->CountLines();
161 textView
->SetExplicitMinSize(BSize(B_SIZE_UNSET
, textHeight
));
163 SetDefaultButton(m_okButton
);
164 if (badPassword
&& previousUser
.Length())
165 m_passwordTextControl
->MakeFocus(true);
167 m_usernameTextControl
->MakeFocus(true);
169 if (m_parentWindowFrame
.IsValid())
170 CenterIn(m_parentWindowFrame
);
174 // Start AuthenticationPanel window thread
177 // Let the window jitter, if the previous password was invalid
179 PostMessage(kMsgJitter
);
181 // Block calling thread
182 // Get the originating window, if it exists, to let it redraw itself.
183 BWindow
* window
= dynamic_cast<BWindow
*>
184 (BLooper::LooperForThread(find_thread(NULL
)));
189 err
= acquire_sem_etc(m_exitSemaphore
, 1, B_RELATIVE_TIMEOUT
,
191 // We've (probably) had our time slice taken away from us
192 } while (err
== B_INTERRUPTED
);
194 if (err
!= B_TIMED_OUT
) {
195 // Semaphore was finally released or nuked.
198 window
->UpdateIfNeeded();
201 // No window to update, so just hang out until we're done.
202 while (acquire_sem(m_exitSemaphore
) == B_INTERRUPTED
) {
206 // AuthenticationPanel wants to quit.
209 user
= m_usernameTextControl
->Text();
210 pass
= m_passwordTextControl
->Text();
211 if (rememberCredentials
)
212 *rememberCredentials
= m_rememberCredentialsCheckBox
->Value()
215 bool canceled
= m_cancelled
;
217 // AuthenticationPanel object is TOAST here.