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 41 using views::Widget; 42 43 namespace { 44 45 gfx::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. 60 chromeos::NetworkConfigView** GetActiveDialogPointer() { 61 static chromeos::NetworkConfigView* active_dialog = NULL; 62 return &active_dialog; 63 } 64 65 chromeos::NetworkConfigView* GetActiveDialog() { 66 return *(GetActiveDialogPointer()); 67 } 68 69 void SetActiveDialog(chromeos::NetworkConfigView* dialog) { 70 *(GetActiveDialogPointer()) = dialog; 71 } 72 73 } // namespace 74 75 namespace chromeos { 76 77 // static 78 const int ChildNetworkConfigView::kInputFieldMinWidth = 270; 79 80 NetworkConfigView::NetworkConfigView() 81 : child_config_view_(NULL), 82 delegate_(NULL), 83 advanced_button_(NULL) { 84 DCHECK(GetActiveDialog() == NULL); 85 SetActiveDialog(this); 86 } 87 88 bool 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 102 bool 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 117 NetworkConfigView::~NetworkConfigView() { 118 DCHECK(GetActiveDialog() == this); 119 SetActiveDialog(NULL); 120 } 121 122 // static 123 void 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 144 void 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 158 gfx::NativeWindow NetworkConfigView::GetNativeWindow() const { 159 return GetWidget()->GetNativeWindow(); 160 } 161 162 base::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 172 bool 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 179 bool NetworkConfigView::Cancel() { 180 if (delegate_) 181 delegate_->OnDialogCancelled(); 182 child_config_view_->Cancel(); 183 return true; 184 } 185 186 bool 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 196 views::View* NetworkConfigView::CreateExtraView() { 197 return advanced_button_; 198 } 199 200 views::View* NetworkConfigView::GetInitiallyFocusedView() { 201 return child_config_view_->GetInitiallyFocusedView(); 202 } 203 204 base::string16 NetworkConfigView::GetWindowTitle() const { 205 DCHECK(!child_config_view_->GetTitle().empty()); 206 return child_config_view_->GetTitle(); 207 } 208 209 ui::ModalType NetworkConfigView::GetModalType() const { 210 return ui::MODAL_TYPE_SYSTEM; 211 } 212 213 void 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 219 void 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 227 void 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 251 void NetworkConfigView::Layout() { 252 child_config_view_->SetBounds(0, 0, width(), height()); 253 } 254 255 gfx::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 266 void 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 275 void 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 290 ChildNetworkConfigView::ChildNetworkConfigView( 291 NetworkConfigView* parent, 292 const std::string& service_path) 293 : parent_(parent), 294 service_path_(service_path) { 295 } 296 297 ChildNetworkConfigView::~ChildNetworkConfigView() { 298 } 299 300 bool ChildNetworkConfigView::IsConfigureDialog() { 301 return false; 302 } 303 304 // static 305 void 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 314 ControlledSettingIndicatorView::ControlledSettingIndicatorView() 315 : managed_(false), 316 image_view_(NULL) { 317 Init(); 318 } 319 320 ControlledSettingIndicatorView::ControlledSettingIndicatorView( 321 const NetworkPropertyUIData& ui_data) 322 : managed_(false), 323 image_view_(NULL) { 324 Init(); 325 Update(ui_data); 326 } 327 328 ControlledSettingIndicatorView::~ControlledSettingIndicatorView() {} 329 330 void 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 339 gfx::Size ControlledSettingIndicatorView::GetPreferredSize() const { 340 return (managed_ && visible()) ? image_view_->GetPreferredSize() 341 : gfx::Size(); 342 } 343 344 void ControlledSettingIndicatorView::Layout() { 345 image_view_->SetBounds(0, 0, width(), height()); 346 } 347 348 void 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