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