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