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/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