network_config_view.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1// Copyright (c) 2012 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/options/network_config_view.h"
6
7#include <algorithm>
8
9#include "ash/shell.h"
10#include "base/strings/string_util.h"
11#include "base/strings/utf_string_conversions.h"
12#include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
13#include "chrome/browser/chromeos/login/users/user.h"
14#include "chrome/browser/chromeos/options/network_property_ui_data.h"
15#include "chrome/browser/chromeos/options/vpn_config_view.h"
16#include "chrome/browser/chromeos/options/wifi_config_view.h"
17#include "chrome/browser/chromeos/options/wimax_config_view.h"
18#include "chrome/browser/profiles/profile_manager.h"
19#include "chrome/browser/ui/browser.h"
20#include "chrome/browser/ui/browser_finder.h"
21#include "chrome/browser/ui/browser_window.h"
22#include "chrome/browser/ui/host_desktop.h"
23#include "chromeos/login/login_state.h"
24#include "chromeos/network/network_state.h"
25#include "chromeos/network/network_state_handler.h"
26#include "grit/chromium_strings.h"
27#include "grit/generated_resources.h"
28#include "grit/locale_settings.h"
29#include "grit/theme_resources.h"
30#include "ui/accessibility/ax_view_state.h"
31#include "ui/aura/window_event_dispatcher.h"
32#include "ui/base/l10n/l10n_util.h"
33#include "ui/base/resource/resource_bundle.h"
34#include "ui/gfx/image/image.h"
35#include "ui/gfx/rect.h"
36#include "ui/views/controls/button/label_button.h"
37#include "ui/views/controls/image_view.h"
38#include "ui/views/layout/layout_constants.h"
39#include "ui/views/widget/widget.h"
40
41using views::Widget;
42
43namespace {
44
45gfx::NativeWindow GetParentForUnhostedDialog() {
46  if (chromeos::LoginDisplayHostImpl::default_host()) {
47    return chromeos::LoginDisplayHostImpl::default_host()->GetNativeWindow();
48  } else {
49    Browser* browser = chrome::FindTabbedBrowser(
50        ProfileManager::GetPrimaryUserProfile(),
51        true,
52        chrome::HOST_DESKTOP_TYPE_ASH);
53    if (browser)
54      return browser->window()->GetNativeWindow();
55  }
56  return NULL;
57}
58
59// Avoid global static initializer.
60chromeos::NetworkConfigView** GetActiveDialogPointer() {
61  static chromeos::NetworkConfigView* active_dialog = NULL;
62  return &active_dialog;
63}
64
65chromeos::NetworkConfigView* GetActiveDialog() {
66  return *(GetActiveDialogPointer());
67}
68
69void SetActiveDialog(chromeos::NetworkConfigView* dialog) {
70  *(GetActiveDialogPointer()) = dialog;
71}
72
73}  // namespace
74
75namespace chromeos {
76
77// static
78const int ChildNetworkConfigView::kInputFieldMinWidth = 270;
79
80NetworkConfigView::NetworkConfigView()
81    : child_config_view_(NULL),
82      delegate_(NULL),
83      advanced_button_(NULL) {
84  DCHECK(GetActiveDialog() == NULL);
85  SetActiveDialog(this);
86}
87
88bool NetworkConfigView::InitWithNetworkState(const NetworkState* network) {
89  DCHECK(network);
90  std::string service_path = network->path();
91  if (network->type() == shill::kTypeWifi ||
92      network->type() == shill::kTypeEthernet) {
93    child_config_view_ = new WifiConfigView(this, service_path, false);
94  } else if (network->type() == shill::kTypeWimax) {
95    child_config_view_ = new WimaxConfigView(this, service_path);
96  } else if (network->type() == shill::kTypeVPN) {
97    child_config_view_ = new VPNConfigView(this, service_path);
98  }
99  return child_config_view_ != NULL;
100}
101
102bool NetworkConfigView::InitWithType(const std::string& type) {
103  if (type == shill::kTypeWifi) {
104    child_config_view_ = new WifiConfigView(this,
105                                            "" /* service_path */,
106                                            false /* show_8021x */);
107    advanced_button_ = new views::LabelButton(this, l10n_util::GetStringUTF16(
108        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_ADVANCED_BUTTON));
109    advanced_button_->SetStyle(views::Button::STYLE_BUTTON);
110  } else if (type == shill::kTypeVPN) {
111    child_config_view_ = new VPNConfigView(this,
112                                           "" /* service_path */);
113  }
114  return child_config_view_ != NULL;
115}
116
117NetworkConfigView::~NetworkConfigView() {
118  DCHECK(GetActiveDialog() == this);
119  SetActiveDialog(NULL);
120}
121
122// static
123void NetworkConfigView::Show(const std::string& service_path,
124                             gfx::NativeWindow parent) {
125  if (GetActiveDialog() != NULL)
126    return;
127  NetworkConfigView* view = new NetworkConfigView();
128  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
129      GetNetworkState(service_path);
130  if (!network) {
131    LOG(ERROR) << "NetworkConfigView::Show called with invalid service_path";
132    return;
133  }
134  if (!view->InitWithNetworkState(network)) {
135    LOG(ERROR) << "NetworkConfigView::Show called with invalid network type: "
136               << network->type();
137    delete view;
138    return;
139  }
140  view->ShowDialog(parent);
141}
142
143// static
144void NetworkConfigView::ShowForType(const std::string& type,
145                                    gfx::NativeWindow parent) {
146  if (GetActiveDialog() != NULL)
147    return;
148  NetworkConfigView* view = new NetworkConfigView();
149  if (!view->InitWithType(type)) {
150    LOG(ERROR) << "NetworkConfigView::ShowForType called with invalid type: "
151               << type;
152    delete view;
153    return;
154  }
155  view->ShowDialog(parent);
156}
157
158gfx::NativeWindow NetworkConfigView::GetNativeWindow() const {
159  return GetWidget()->GetNativeWindow();
160}
161
162base::string16 NetworkConfigView::GetDialogButtonLabel(
163    ui::DialogButton button) const {
164  if (button == ui::DIALOG_BUTTON_OK) {
165    if (child_config_view_->IsConfigureDialog())
166      return l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_CONFIGURE);
167    return l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_CONNECT);
168  }
169  return views::DialogDelegateView::GetDialogButtonLabel(button);
170}
171
172bool NetworkConfigView::IsDialogButtonEnabled(ui::DialogButton button) const {
173  // Disable connect button if cannot login.
174  if (button == ui::DIALOG_BUTTON_OK)
175    return child_config_view_->CanLogin();
176  return true;
177}
178
179bool NetworkConfigView::Cancel() {
180  if (delegate_)
181    delegate_->OnDialogCancelled();
182  child_config_view_->Cancel();
183  return true;
184}
185
186bool NetworkConfigView::Accept() {
187  // Do not attempt login if it is guaranteed to fail, keep the dialog open.
188  if (!child_config_view_->CanLogin())
189    return false;
190  bool result = child_config_view_->Login();
191  if (result && delegate_)
192    delegate_->OnDialogAccepted();
193  return result;
194}
195
196views::View* NetworkConfigView::CreateExtraView() {
197  return advanced_button_;
198}
199
200views::View* NetworkConfigView::GetInitiallyFocusedView() {
201  return child_config_view_->GetInitiallyFocusedView();
202}
203
204base::string16 NetworkConfigView::GetWindowTitle() const {
205  DCHECK(!child_config_view_->GetTitle().empty());
206  return child_config_view_->GetTitle();
207}
208
209ui::ModalType NetworkConfigView::GetModalType() const {
210  return ui::MODAL_TYPE_SYSTEM;
211}
212
213void NetworkConfigView::GetAccessibleState(ui::AXViewState* state) {
214  state->name =
215      l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_OTHER_WIFI_NETWORKS);
216  state->role = ui::AX_ROLE_DIALOG;
217}
218
219void NetworkConfigView::ButtonPressed(views::Button* sender,
220                                      const ui::Event& event) {
221  if (advanced_button_ && sender == advanced_button_) {
222    advanced_button_->SetVisible(false);
223    ShowAdvancedView();
224  }
225}
226
227void NetworkConfigView::ShowAdvancedView() {
228  // Clear out the old widgets and build new ones.
229  RemoveChildView(child_config_view_);
230  delete child_config_view_;
231  // For now, there is only an advanced view for Wi-Fi 802.1X.
232  child_config_view_ = new WifiConfigView(this,
233                                          "" /* service_path */,
234                                          true /* show_8021x */);
235  AddChildView(child_config_view_);
236  // Resize the window to be able to hold the new widgets.
237  gfx::Size size = views::Widget::GetLocalizedContentsSize(
238      IDS_JOIN_WIFI_NETWORK_DIALOG_ADVANCED_WIDTH_CHARS,
239      IDS_JOIN_WIFI_NETWORK_DIALOG_ADVANCED_MINIMUM_HEIGHT_LINES);
240  // Get the new bounds with desired size at the same center point.
241  gfx::Rect bounds = GetWidget()->GetWindowBoundsInScreen();
242  int horiz_padding = bounds.width() - size.width();
243  int vert_padding = bounds.height() - size.height();
244  bounds.Inset(horiz_padding / 2, vert_padding / 2,
245               horiz_padding / 2, vert_padding / 2);
246  GetWidget()->SetBoundsConstrained(bounds);
247  Layout();
248  child_config_view_->InitFocus();
249}
250
251void NetworkConfigView::Layout() {
252  child_config_view_->SetBounds(0, 0, width(), height());
253}
254
255gfx::Size NetworkConfigView::GetPreferredSize() const {
256  gfx::Size result(views::Widget::GetLocalizedContentsSize(
257      IDS_JOIN_WIFI_NETWORK_DIALOG_WIDTH_CHARS,
258      IDS_JOIN_WIFI_NETWORK_DIALOG_MINIMUM_HEIGHT_LINES));
259  gfx::Size size = child_config_view_->GetPreferredSize();
260  result.set_height(size.height());
261  if (size.width() > result.width())
262    result.set_width(size.width());
263  return result;
264}
265
266void NetworkConfigView::ViewHierarchyChanged(
267    const ViewHierarchyChangedDetails& details) {
268  // Can't init before we're inserted into a Container, because we require
269  // a HWND to parent native child controls to.
270  if (details.is_add && details.child == this) {
271    AddChildView(child_config_view_);
272  }
273}
274
275void NetworkConfigView::ShowDialog(gfx::NativeWindow parent) {
276  if (parent == NULL)
277    parent = GetParentForUnhostedDialog();
278  // Failed connections may result in a pop-up with no natural parent window,
279  // so provide a fallback context on the primary display. This is necessary
280  // becase one of parent or context must be non NULL.
281  gfx::NativeWindow context =
282      parent ? NULL : ash::Shell::GetPrimaryRootWindow();
283  Widget* window = DialogDelegate::CreateDialogWidget(this, context, parent);
284  window->SetAlwaysOnTop(true);
285  window->Show();
286}
287
288// ChildNetworkConfigView
289
290ChildNetworkConfigView::ChildNetworkConfigView(
291    NetworkConfigView* parent,
292    const std::string& service_path)
293    : parent_(parent),
294      service_path_(service_path) {
295}
296
297ChildNetworkConfigView::~ChildNetworkConfigView() {
298}
299
300bool ChildNetworkConfigView::IsConfigureDialog() {
301  return false;
302}
303
304// static
305void ChildNetworkConfigView::GetShareStateForLoginState(bool* default_value,
306                                                        bool* modifiable) {
307  *default_value = !LoginState::Get()->UserHasNetworkProfile();
308  // Allow only authenticated user to change the share state.
309  *modifiable = LoginState::Get()->IsUserAuthenticated();
310}
311
312// ControlledSettingIndicatorView
313
314ControlledSettingIndicatorView::ControlledSettingIndicatorView()
315    : managed_(false),
316      image_view_(NULL) {
317  Init();
318}
319
320ControlledSettingIndicatorView::ControlledSettingIndicatorView(
321    const NetworkPropertyUIData& ui_data)
322    : managed_(false),
323      image_view_(NULL) {
324  Init();
325  Update(ui_data);
326}
327
328ControlledSettingIndicatorView::~ControlledSettingIndicatorView() {}
329
330void ControlledSettingIndicatorView::Update(
331    const NetworkPropertyUIData& ui_data) {
332  if (managed_ == ui_data.IsManaged())
333    return;
334
335  managed_ = ui_data.IsManaged();
336  PreferredSizeChanged();
337}
338
339gfx::Size ControlledSettingIndicatorView::GetPreferredSize() const {
340  return (managed_ && visible()) ? image_view_->GetPreferredSize()
341                                 : gfx::Size();
342}
343
344void ControlledSettingIndicatorView::Layout() {
345  image_view_->SetBounds(0, 0, width(), height());
346}
347
348void ControlledSettingIndicatorView::Init() {
349  image_ = ResourceBundle::GetSharedInstance().GetImageNamed(
350      IDR_CONTROLLED_SETTING_MANDATORY).ToImageSkia();
351  image_view_ = new views::ImageView();
352  // Disable |image_view_| so mouse events propagate to the parent.
353  image_view_->SetEnabled(false);
354  image_view_->SetImage(image_);
355  image_view_->SetTooltipText(
356      l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_POLICY));
357  AddChildView(image_view_);
358}
359
360}  // namespace chromeos
361