Home | History | Annotate | Download | only in options
      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