• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/chromeos/login/network_selection_view.h"
6 
7 #include <signal.h>
8 #include <sys/types.h>
9 #include <string>
10 
11 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/chromeos/login/helper.h"
13 #include "chrome/browser/chromeos/login/keyboard_switch_menu.h"
14 #include "chrome/browser/chromeos/login/language_switch_menu.h"
15 #include "chrome/browser/chromeos/login/network_screen_delegate.h"
16 #include "chrome/browser/chromeos/login/proxy_settings_dialog.h"
17 #include "chrome/browser/chromeos/login/rounded_rect_painter.h"
18 #include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
19 #include "chrome/browser/chromeos/status/network_dropdown_button.h"
20 #include "grit/chromium_strings.h"
21 #include "grit/generated_resources.h"
22 #include "grit/theme_resources.h"
23 #include "ui/base/l10n/l10n_util.h"
24 #include "ui/base/resource/resource_bundle.h"
25 #include "ui/gfx/size.h"
26 #include "views/controls/label.h"
27 #include "views/controls/throbber.h"
28 #include "views/layout/fill_layout.h"
29 #include "views/layout/grid_layout.h"
30 #include "views/layout/layout_constants.h"
31 #include "views/widget/widget.h"
32 #include "views/widget/widget_gtk.h"
33 #include "views/window/non_client_view.h"
34 #include "views/window/window.h"
35 #include "views/window/window_gtk.h"
36 
37 using views::Background;
38 using views::GridLayout;
39 using views::Label;
40 using views::View;
41 using views::Widget;
42 using views::WidgetGtk;
43 
44 namespace {
45 
46 enum kLayoutColumnsets {
47   STANDARD_ROW,
48   THROBBER_ROW,
49 };
50 
51 enum kContentsLayoutColumnsets {
52   WELCOME_ROW,
53   CONTENTS_ROW,
54 };
55 
56 // Grid layout constants.
57 const int kBorderSize = 10;
58 const int kWelcomeTitlePadding = 10;
59 const int kPaddingColumnWidth = 55;
60 const int kMediumPaddingColumnWidth = 20;
61 const int kControlPaddingRow = 15;
62 
63 // Fixed size for language/keyboard/network controls height.
64 const int kSelectionBoxHeight = 29;
65 
66 // Menu button is drawn using our custom icons in resources. See
67 // TextButtonBorder::OnPaint() for details. So this offset compensate
68 // horizontal size, eaten by those icons.
69 const int kMenuHorizontalOffset = -3;
70 
71 // Vertical addition to the menu window to make it appear exactly below
72 // MenuButton.
73 const int kMenuVerticalOffset = -1;
74 
75 // Offset that compensates menu width so that it matches
76 // menu button visual width when being in pushed state.
77 const int kMenuWidthOffset = 6;
78 
79 const SkColor kWelcomeColor = 0xFFCDD3D6;
80 
81 // Initializes menu button default properties.
InitMenuButtonProperties(views::MenuButton * menu_button)82 static void InitMenuButtonProperties(views::MenuButton* menu_button) {
83   menu_button->SetFocusable(true);
84   menu_button->SetNormalHasBorder(true);
85   menu_button->SetEnabledColor(SK_ColorBLACK);
86   menu_button->SetHighlightColor(SK_ColorBLACK);
87   menu_button->SetHoverColor(SK_ColorBLACK);
88   menu_button->set_animate_on_state_change(false);
89   // Menu is positioned by bottom right corner of the MenuButton.
90   menu_button->set_menu_offset(kMenuHorizontalOffset, kMenuVerticalOffset);
91 }
92 
SetMenuButtonFont(views::MenuButton * menu_button,const gfx::Font & font)93 static void SetMenuButtonFont(views::MenuButton* menu_button,
94                               const gfx::Font& font) {
95   menu_button->SetFont(font);
96   chromeos::CorrectMenuButtonFontSize(menu_button);
97 }
98 
99 }  // namespace
100 
101 namespace chromeos {
102 
103 // NetworkDropdownButton with custom Activate() behavior.
104 class NetworkControlReportOnActivate : public NetworkDropdownButton {
105  public:
NetworkControlReportOnActivate(bool browser_mode,gfx::NativeWindow parent_window,NetworkScreenDelegate * delegate)106   NetworkControlReportOnActivate(bool browser_mode,
107                                  gfx::NativeWindow parent_window,
108                                  NetworkScreenDelegate* delegate)
109       : NetworkDropdownButton(browser_mode, parent_window),
110         delegate_(delegate) {}
111 
112   // Overridden from MenuButton:
Activate()113   virtual bool Activate() {
114     delegate_->ClearErrors();
115     return MenuButton::Activate();
116   }
117 
118  private:
119   NetworkScreenDelegate* delegate_;
120 
121   DISALLOW_COPY_AND_ASSIGN(NetworkControlReportOnActivate);
122 };
123 
124 // MenuButton with custom processing on focus events.
125 class NotifyingMenuButton : public DropDownButton {
126  public:
NotifyingMenuButton(views::ButtonListener * listener,const std::wstring & text,views::ViewMenuDelegate * menu_delegate,bool show_menu_marker,NetworkScreenDelegate * delegate)127   NotifyingMenuButton(views::ButtonListener* listener,
128                       const std::wstring& text,
129                       views::ViewMenuDelegate* menu_delegate,
130                       bool show_menu_marker,
131                       NetworkScreenDelegate* delegate)
132       : DropDownButton(listener, text, menu_delegate, show_menu_marker),
133         delegate_(delegate) {}
134 
135   // Overridden from View:
OnFocus()136   virtual void OnFocus() OVERRIDE {
137     delegate_->ClearErrors();
138     GetWidget()->NotifyAccessibilityEvent(
139         this, ui::AccessibilityTypes::EVENT_FOCUS, true);
140   }
141 
142  private:
143   NetworkScreenDelegate* delegate_;
144 
145   DISALLOW_COPY_AND_ASSIGN(NotifyingMenuButton);
146 };
147 
NetworkSelectionView(NetworkScreenDelegate * delegate)148 NetworkSelectionView::NetworkSelectionView(NetworkScreenDelegate* delegate)
149     : entire_screen_view_(NULL),
150       contents_view_(NULL),
151       languages_menubutton_(NULL),
152       keyboards_menubutton_(NULL),
153       welcome_label_(NULL),
154       select_language_label_(NULL),
155       select_keyboard_label_(NULL),
156       select_network_label_(NULL),
157       connecting_network_label_(NULL),
158       network_dropdown_(NULL),
159       continue_button_(NULL),
160       throbber_(CreateDefaultSmoothedThrobber()),
161       proxy_settings_link_(NULL),
162       show_keyboard_button_(false),
163       delegate_(delegate) {
164 }
165 
~NetworkSelectionView()166 NetworkSelectionView::~NetworkSelectionView() {
167   throbber_->Stop();
168   throbber_ = NULL;
169 }
170 
AddControlsToLayout(views::GridLayout * contents_layout)171 void NetworkSelectionView::AddControlsToLayout(
172     views::GridLayout* contents_layout) {
173   // Padding rows will be resized.
174   const int kPadding = 0;
175   if (IsConnecting()) {
176     contents_layout->AddPaddingRow(1, kPadding);
177     contents_layout->StartRow(0, THROBBER_ROW);
178     contents_layout->AddView(connecting_network_label_);
179     contents_layout->AddView(throbber_);
180     contents_layout->AddPaddingRow(1, kPadding);
181   } else {
182     contents_layout->AddPaddingRow(1, kPadding);
183     contents_layout->StartRow(0, STANDARD_ROW);
184     contents_layout->AddView(select_language_label_);
185     contents_layout->AddView(languages_menubutton_, 1, 1,
186                     GridLayout::FILL, GridLayout::FILL,
187                     languages_menubutton_->GetPreferredSize().width(),
188                     kSelectionBoxHeight);
189     if (show_keyboard_button_) {
190       contents_layout->AddPaddingRow(0, kControlPaddingRow);
191       contents_layout->StartRow(0, STANDARD_ROW);
192       contents_layout->AddView(select_keyboard_label_);
193       contents_layout->AddView(
194           keyboards_menubutton_, 1, 1,
195           GridLayout::FILL, GridLayout::FILL,
196           keyboards_menubutton_->GetPreferredSize().width(),
197           kSelectionBoxHeight);
198     }
199     contents_layout->AddPaddingRow(0, kControlPaddingRow);
200     contents_layout->StartRow(0, STANDARD_ROW);
201     contents_layout->AddView(select_network_label_);
202     contents_layout->AddView(network_dropdown_, 1, 1,
203                     GridLayout::FILL, GridLayout::FILL,
204                     network_dropdown_->GetPreferredSize().width(),
205                     kSelectionBoxHeight);
206     contents_layout->AddPaddingRow(0, kControlPaddingRow);
207     contents_layout->StartRow(0, STANDARD_ROW);
208     contents_layout->SkipColumns(1);
209     contents_layout->AddView(proxy_settings_link_, 1, 1,
210                     GridLayout::LEADING, GridLayout::CENTER);
211     contents_layout->AddPaddingRow(0, kControlPaddingRow);
212     contents_layout->StartRow(0, STANDARD_ROW);
213     contents_layout->SkipColumns(1);
214     contents_layout->AddView(continue_button_, 1, 1,
215                     GridLayout::LEADING, GridLayout::CENTER);
216     contents_layout->AddPaddingRow(1, kPadding);
217   }
218 }
219 
InitLayout()220 void NetworkSelectionView::InitLayout() {
221   gfx::Size screen_size = delegate_->size();
222   const int widest_label = std::max(
223       std::max(
224           select_language_label_->GetPreferredSize().width(),
225           select_keyboard_label_->GetPreferredSize().width()),
226       select_network_label_->GetPreferredSize().width());
227   const int dropdown_width = screen_size.width() - 2 * kBorderSize -
228       2 * kPaddingColumnWidth - kMediumPaddingColumnWidth - widest_label;
229   delegate_->language_switch_menu()->SetFirstLevelMenuWidth(
230       dropdown_width - kMenuWidthOffset);
231   delegate_->keyboard_switch_menu()->SetMinimumWidth(
232       dropdown_width - kMenuWidthOffset);
233   network_dropdown_->SetFirstLevelMenuWidth(dropdown_width - kMenuWidthOffset);
234 
235   // Define layout and column set for entire screen (title + screen).
236   SetLayoutManager(new views::FillLayout);
237   views::GridLayout* screen_layout = new views::GridLayout(entire_screen_view_);
238   entire_screen_view_->SetLayoutManager(screen_layout);
239 
240   views::ColumnSet* column_set = screen_layout->AddColumnSet(WELCOME_ROW);
241   const int welcome_width = screen_size.width() - 2 * kWelcomeTitlePadding -
242       2 * kBorderSize;
243   column_set->AddPaddingColumn(0, kWelcomeTitlePadding + kBorderSize);
244   column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
245                         GridLayout::FIXED, welcome_width, welcome_width);
246   column_set->AddPaddingColumn(0, kWelcomeTitlePadding + kBorderSize);
247   column_set = screen_layout->AddColumnSet(CONTENTS_ROW);
248   column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
249       GridLayout::FIXED, screen_size.width(), screen_size.width());
250   screen_layout->StartRow(0, WELCOME_ROW);
251   screen_layout->AddView(welcome_label_);
252   screen_layout->StartRow(1, CONTENTS_ROW);
253   screen_layout->AddView(contents_view_);
254 
255   // Define layout and column set for screen contents.
256   views::GridLayout* contents_layout = new views::GridLayout(contents_view_);
257   contents_view_->SetLayoutManager(contents_layout);
258 
259   column_set = contents_layout->AddColumnSet(STANDARD_ROW);
260   column_set->AddPaddingColumn(1, kPaddingColumnWidth);
261   column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0,
262                         GridLayout::FIXED, widest_label, widest_label);
263   column_set->AddPaddingColumn(0, kMediumPaddingColumnWidth);
264   column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
265                         GridLayout::FIXED, dropdown_width, dropdown_width);
266   column_set->AddPaddingColumn(1, kPaddingColumnWidth);
267 
268   const int h_padding = 30;
269   column_set = contents_layout->AddColumnSet(THROBBER_ROW);
270   column_set->AddPaddingColumn(1, h_padding);
271   column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
272                         GridLayout::USE_PREF, 0, 0);
273   column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
274   column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1,
275                         GridLayout::USE_PREF, 0, 0);
276   column_set->AddPaddingColumn(1, h_padding);
277 
278   AddControlsToLayout(contents_layout);
279 }
280 
Init()281 void NetworkSelectionView::Init() {
282   contents_view_ = new views::View();
283 
284   entire_screen_view_ = new views::View();
285   AddChildView(entire_screen_view_);
286 
287   // Use rounded rect background.
288   views::Painter* painter = CreateWizardPainter(
289       &BorderDefinition::kScreenBorder);
290   contents_view_->set_background(
291       views::Background::CreateBackgroundPainter(true, painter));
292 
293   welcome_label_ = new views::Label();
294   welcome_label_->SetColor(kWelcomeColor);
295   welcome_label_->SetMultiLine(true);
296 
297   select_language_label_ = new views::Label();
298 
299   languages_menubutton_ = new NotifyingMenuButton(
300       NULL, std::wstring(), delegate_->language_switch_menu(), true, delegate_);
301   InitMenuButtonProperties(languages_menubutton_);
302 
303   select_keyboard_label_ = new views::Label();
304 
305   keyboards_menubutton_ = new DropDownButton(
306       NULL /* listener */, L"", delegate_->keyboard_switch_menu(),
307       true /* show_menu_marker */);
308   InitMenuButtonProperties(keyboards_menubutton_);
309 
310   select_network_label_ = new views::Label();
311 
312   network_dropdown_ = new NetworkControlReportOnActivate(false,
313                                                          GetNativeWindow(),
314                                                          delegate_);
315   InitMenuButtonProperties(network_dropdown_);
316 
317   connecting_network_label_ = new views::Label();
318   connecting_network_label_->SetVisible(false);
319 
320   proxy_settings_link_ = new views::Link();
321   proxy_settings_link_->SetController(this);
322   proxy_settings_link_->SetVisible(true);
323   proxy_settings_link_->SetFocusable(true);
324   proxy_settings_link_->SetNormalColor(login::kLinkColor);
325   proxy_settings_link_->SetHighlightedColor(login::kLinkColor);
326 
327   UpdateLocalizedStringsAndFonts();
328 }
329 
UpdateLocalizedStringsAndFonts()330 void NetworkSelectionView::UpdateLocalizedStringsAndFonts() {
331   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
332   gfx::Font welcome_label_font = rb.GetFont(ResourceBundle::LargeFont).
333       DeriveFont(kWelcomeTitleFontDelta, gfx::Font::BOLD);
334   gfx::Font select_label_font = rb.GetFont(ResourceBundle::MediumFont).
335       DeriveFont(kNetworkSelectionLabelFontDelta);
336   const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont);
337 
338   SetMenuButtonFont(languages_menubutton_, base_font);
339   languages_menubutton_->SetText(
340       UTF16ToWide(delegate_->language_switch_menu()->GetCurrentLocaleName()));
341   SetMenuButtonFont(keyboards_menubutton_, base_font);
342   keyboards_menubutton_->SetText(
343       UTF16ToWide(delegate_->keyboard_switch_menu()->GetCurrentKeyboardName()));
344   welcome_label_->SetFont(welcome_label_font);
345   welcome_label_->SetText(
346       UTF16ToWide(l10n_util::GetStringUTF16(IDS_NETWORK_SELECTION_TITLE)));
347   select_language_label_->SetFont(select_label_font);
348   select_language_label_->SetText(
349       UTF16ToWide(l10n_util::GetStringUTF16(IDS_LANGUAGE_SELECTION_SELECT)));
350   languages_menubutton_->SetAccessibleName(
351       l10n_util::GetStringUTF16(IDS_LANGUAGE_SELECTION_SELECT));
352   select_keyboard_label_->SetFont(select_label_font);
353   select_keyboard_label_->SetText(
354       UTF16ToWide(l10n_util::GetStringUTF16(IDS_KEYBOARD_SELECTION_SELECT)));
355   keyboards_menubutton_->SetAccessibleName(
356       l10n_util::GetStringUTF16(IDS_KEYBOARD_SELECTION_SELECT));
357   select_network_label_->SetFont(select_label_font);
358   select_network_label_->SetText(
359       UTF16ToWide(l10n_util::GetStringUTF16(IDS_NETWORK_SELECTION_SELECT)));
360   SetMenuButtonFont(network_dropdown_, base_font);
361   network_dropdown_->SetAccessibleName(
362       l10n_util::GetStringUTF16(IDS_NETWORK_SELECTION_SELECT));
363   proxy_settings_link_->SetFont(base_font);
364   proxy_settings_link_->SetText(UTF16ToWide(
365       l10n_util::GetStringUTF16(IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON)));
366   connecting_network_label_->SetFont(rb.GetFont(ResourceBundle::MediumFont));
367   RecreateNativeControls();
368   UpdateConnectingNetworkLabel();
369   network_dropdown_->Refresh();
370   InitLayout();
371 }
372 
373 ////////////////////////////////////////////////////////////////////////////////
374 // views::View: implementation:
375 
OnKeyPressed(const views::KeyEvent &)376 bool NetworkSelectionView::OnKeyPressed(const views::KeyEvent&) {
377   if (delegate_->is_error_shown()) {
378     delegate_->ClearErrors();
379     return true;
380   }
381   return false;
382 }
383 
OnLocaleChanged()384 void NetworkSelectionView::OnLocaleChanged() {
385   show_keyboard_button_ = true;
386   UpdateLocalizedStringsAndFonts();
387   // Proxy settings dialog contains localized title.  Zap it.
388   proxy_settings_dialog_.reset(NULL);
389 
390   Layout();
391   SchedulePaint();
392 }
393 
394 ////////////////////////////////////////////////////////////////////////////////
395 // NetworkSelectionView, public:
396 
GetNativeWindow() const397 gfx::NativeWindow NetworkSelectionView::GetNativeWindow() const {
398   return
399       GTK_WINDOW(static_cast<const WidgetGtk*>(GetWidget())->GetNativeView());
400 }
401 
GetNetworkControlView() const402 views::View* NetworkSelectionView::GetNetworkControlView() const {
403   return network_dropdown_;
404 }
405 
ShowConnectingStatus(bool connecting,const string16 & network_id)406 void NetworkSelectionView::ShowConnectingStatus(bool connecting,
407                                                 const string16& network_id) {
408   network_id_ = network_id;
409   UpdateConnectingNetworkLabel();
410   select_language_label_->SetVisible(!connecting);
411   languages_menubutton_->SetVisible(!connecting);
412   select_keyboard_label_->SetVisible(!connecting);
413   keyboards_menubutton_->SetVisible(!connecting);
414   select_network_label_->SetVisible(!connecting);
415   network_dropdown_->SetVisible(!connecting);
416   continue_button_->SetVisible(!connecting);
417   proxy_settings_link_->SetVisible(!connecting);
418   connecting_network_label_->SetVisible(connecting);
419   InitLayout();
420   Layout();
421   if (connecting) {
422     throbber_->Start();
423     network_dropdown_->CancelMenu();
424   } else {
425     throbber_->Stop();
426   }
427 }
428 
IsConnecting() const429 bool NetworkSelectionView::IsConnecting() const {
430   return connecting_network_label_->IsVisible();
431 }
432 
EnableContinue(bool enabled)433 void NetworkSelectionView::EnableContinue(bool enabled) {
434   if (continue_button_)
435     continue_button_->SetEnabled(enabled);
436 }
437 
IsContinueEnabled() const438 bool NetworkSelectionView::IsContinueEnabled() const {
439   return continue_button_ && continue_button_->IsEnabled();
440 }
441 
442 ////////////////////////////////////////////////////////////////////////////////
443 // views::LinkController implementation:
444 
LinkActivated(views::Link * source,int)445 void NetworkSelectionView::LinkActivated(views::Link* source, int) {
446   delegate_->ClearErrors();
447   if (source == proxy_settings_link_) {
448     if (!proxy_settings_dialog_.get()) {
449       proxy_settings_dialog_.reset(
450           new ProxySettingsDialog(this, GetNativeWindow()));
451     }
452     proxy_settings_dialog_->Show();
453   }
454 }
455 
456 ////////////////////////////////////////////////////////////////////////////////
457 // NetworkSelectionView, private:
458 
RecreateNativeControls()459 void NetworkSelectionView::RecreateNativeControls() {
460   // There is no way to get native button preferred size after the button was
461   // sized so delete and recreate the button on text update.
462   bool is_continue_enabled = IsContinueEnabled();
463   delete continue_button_;
464   continue_button_ = new login::WideButton(
465       delegate_,
466       UTF16ToWide(
467           l10n_util::GetStringUTF16(IDS_NETWORK_SELECTION_CONTINUE_BUTTON)));
468   continue_button_->SetEnabled(is_continue_enabled);
469 }
470 
UpdateConnectingNetworkLabel()471 void NetworkSelectionView::UpdateConnectingNetworkLabel() {
472   connecting_network_label_->SetText(UTF16ToWide(l10n_util::GetStringFUTF16(
473       IDS_NETWORK_SELECTION_CONNECTING, network_id_)));
474 }
475 
476 }  // namespace chromeos
477