network_menu.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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/status/network_menu.h"
6
7#include <algorithm>
8
9#include "ash/shell.h"
10#include "ash/shell_delegate.h"
11#include "ash/system/chromeos/network/network_connect.h"
12#include "ash/system/chromeos/network/network_icon.h"
13#include "base/bind.h"
14#include "base/logging.h"
15#include "base/strings/stringprintf.h"
16#include "base/strings/utf_string_conversions.h"
17#include "chrome/browser/chromeos/choose_mobile_network_dialog.h"
18#include "chrome/browser/chromeos/login/user_manager.h"
19#include "chrome/browser/chromeos/mobile_config.h"
20#include "chrome/browser/chromeos/options/network_config_view.h"
21#include "chrome/browser/chromeos/sim_dialog_delegate.h"
22#include "chrome/browser/defaults.h"
23#include "chrome/browser/profiles/profile_manager.h"
24#include "chrome/common/url_constants.h"
25#include "chromeos/network/device_state.h"
26#include "chromeos/network/network_state.h"
27#include "chromeos/network/network_state_handler.h"
28#include "chromeos/network/shill_property_util.h"
29#include "grit/ash_resources.h"
30#include "grit/ash_strings.h"
31#include "grit/generated_resources.h"
32#include "third_party/cros_system_api/dbus/service_constants.h"
33#include "ui/base/l10n/l10n_util.h"
34#include "ui/base/models/menu_model.h"
35#include "ui/base/resource/resource_bundle.h"
36#include "ui/gfx/image/image_skia.h"
37
38namespace chromeos {
39
40namespace {
41
42// Offsets for views menu ids (main menu and submenu ids use the same
43// namespace).
44const int kMainIndexMask = 0x1000;
45const int kMoreIndexMask = 0x4000;
46
47// Replace '&' in a string with "&&" to allow it to be a menu item label.
48std::string EscapeAmpersands(const std::string& input) {
49  std::string str = input;
50  size_t found = str.find('&');
51  while (found != std::string::npos) {
52    str.replace(found, 1, "&&");
53    found = str.find('&', found + 2);
54  }
55  return str;
56}
57
58// Highlight any connected or connecting networks in the UI.
59bool ShouldHighlightNetwork(const NetworkState* network) {
60  return network->IsConnectedState() || network->IsConnectingState();
61}
62
63void ToggleTechnology(const NetworkTypePattern& technology) {
64  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
65  bool is_enabled = handler->IsTechnologyEnabled(technology);
66  ash::network_connect::SetTechnologyEnabled(technology, !is_enabled);
67}
68
69}  // namespace
70
71class NetworkMenuModel : public ui::MenuModel {
72 public:
73  struct MenuItem {
74    MenuItem()
75        : type(ui::MenuModel::TYPE_SEPARATOR),
76          sub_menu_model(NULL),
77          flags(0) {
78    }
79    MenuItem(ui::MenuModel::ItemType type, string16 label, gfx::ImageSkia icon,
80             const std::string& service_path, int flags)
81        : type(type),
82          label(label),
83          icon(icon),
84          service_path(service_path),
85          sub_menu_model(NULL),
86          flags(flags) {
87    }
88    MenuItem(ui::MenuModel::ItemType type, string16 label, gfx::ImageSkia icon,
89             NetworkMenuModel* sub_menu_model, int flags)
90        : type(type),
91          label(label),
92          icon(icon),
93          sub_menu_model(sub_menu_model),
94          flags(flags) {
95    }
96
97    ui::MenuModel::ItemType type;
98    string16 label;
99    gfx::ImageSkia icon;
100    std::string service_path;
101    NetworkMenuModel* sub_menu_model;  // Weak ptr.
102    int flags;
103  };
104  typedef std::vector<MenuItem> MenuItemVector;
105
106  explicit NetworkMenuModel(const base::WeakPtr<NetworkMenu>& owner)
107    : owner_(owner) {}
108  virtual ~NetworkMenuModel() {}
109
110  // Connect or reconnect to the network at |index|.
111  void ConnectToNetworkAt(int index);
112
113  // Called by NetworkMenu::UpdateMenu to initialize menu items.
114  virtual void InitMenuItems(bool should_open_button_options) = 0;
115
116  // Menu item field accessors.
117  const MenuItemVector& menu_items() const { return menu_items_; }
118
119  // ui::MenuModel implementation
120  // GetCommandIdAt() must be implemented by subclasses.
121  virtual bool HasIcons() const OVERRIDE;
122  virtual int GetItemCount() const OVERRIDE;
123  virtual ui::MenuModel::ItemType GetTypeAt(int index) const OVERRIDE;
124  virtual ui::MenuSeparatorType GetSeparatorTypeAt(int index) const OVERRIDE;
125  virtual string16 GetLabelAt(int index) const OVERRIDE;
126  virtual bool IsItemDynamicAt(int index) const OVERRIDE;
127  virtual const gfx::Font* GetLabelFontAt(int index) const OVERRIDE;
128  virtual bool GetAcceleratorAt(int index,
129                                ui::Accelerator* accelerator) const OVERRIDE;
130  virtual bool IsItemCheckedAt(int index) const OVERRIDE;
131  virtual int GetGroupIdAt(int index) const OVERRIDE;
132  virtual bool GetIconAt(int index, gfx::Image* icon) OVERRIDE;
133  virtual ui::ButtonMenuItemModel* GetButtonMenuItemAt(
134      int index) const OVERRIDE;
135  virtual bool IsEnabledAt(int index) const OVERRIDE;
136  virtual bool IsVisibleAt(int index) const OVERRIDE;
137  virtual ui::MenuModel* GetSubmenuModelAt(int index) const OVERRIDE;
138  virtual void HighlightChangedTo(int index) OVERRIDE;
139  virtual void ActivatedAt(int index) OVERRIDE;
140  virtual void SetMenuModelDelegate(ui::MenuModelDelegate* delegate) OVERRIDE;
141  virtual ui::MenuModelDelegate* GetMenuModelDelegate() const OVERRIDE;
142
143 protected:
144  enum MenuItemFlags {
145    FLAG_NONE              = 0,
146    FLAG_DISABLED          = 1 << 0,
147    FLAG_TOGGLE_WIFI       = 1 << 2,
148    FLAG_TOGGLE_MOBILE     = 1 << 3,
149    FLAG_ASSOCIATED        = 1 << 5,
150    FLAG_ETHERNET          = 1 << 6,
151    FLAG_WIFI              = 1 << 7,
152    FLAG_WIMAX             = 1 << 8,
153    FLAG_CELLULAR          = 1 << 9,
154    FLAG_OPTIONS           = 1 << 10,
155    FLAG_ADD_WIFI          = 1 << 11,
156    FLAG_ADD_CELLULAR      = 1 << 12,
157  };
158
159  // Our menu items.
160  MenuItemVector menu_items_;
161
162  // Weak pointer to NetworkMenu that owns this MenuModel.
163  base::WeakPtr<NetworkMenu> owner_;
164
165 private:
166  // Open a dialog to set up and connect to a network.
167  void ShowOther(const std::string& type) const;
168
169  DISALLOW_COPY_AND_ASSIGN(NetworkMenuModel);
170};
171
172class MoreMenuModel : public NetworkMenuModel {
173 public:
174  explicit MoreMenuModel(const base::WeakPtr<NetworkMenu> owner)
175    : NetworkMenuModel(owner) {}
176  virtual ~MoreMenuModel() {}
177
178  // NetworkMenuModel implementation.
179  virtual void InitMenuItems(bool should_open_button_options) OVERRIDE;
180
181  // ui::MenuModel implementation
182  virtual int GetCommandIdAt(int index) const OVERRIDE;
183
184 private:
185  DISALLOW_COPY_AND_ASSIGN(MoreMenuModel);
186};
187
188class MainMenuModel : public NetworkMenuModel {
189 public:
190  explicit MainMenuModel(const base::WeakPtr<NetworkMenu>& owner)
191      : NetworkMenuModel(owner),
192        more_menu_model_(new MoreMenuModel(owner)) {
193  }
194  virtual ~MainMenuModel() {}
195
196  // NetworkMenuModel implementation.
197  virtual void InitMenuItems(bool should_open_button_options) OVERRIDE;
198
199  // ui::MenuModel implementation
200  virtual int GetCommandIdAt(int index) const OVERRIDE;
201
202 private:
203  void AddWirelessNetworkMenuItem(const NetworkState* wifi_network, int flag);
204  void AddMessageItem(const string16& msg);
205
206  scoped_ptr<MoreMenuModel> more_menu_model_;
207
208  DISALLOW_COPY_AND_ASSIGN(MainMenuModel);
209};
210
211////////////////////////////////////////////////////////////////////////////////
212// NetworkMenuModel, public methods:
213
214void NetworkMenuModel::ConnectToNetworkAt(int index) {
215  const std::string& service_path = menu_items_[index].service_path;
216  gfx::NativeWindow native_window = owner_->delegate()->GetNativeWindow();
217  ash::network_connect::ConnectToNetwork(service_path, native_window);
218}
219
220////////////////////////////////////////////////////////////////////////////////
221// NetworkMenuModel, ui::MenuModel implementation:
222
223bool NetworkMenuModel::HasIcons() const {
224  return true;
225}
226
227int NetworkMenuModel::GetItemCount() const {
228  return static_cast<int>(menu_items_.size());
229}
230
231ui::MenuModel::ItemType NetworkMenuModel::GetTypeAt(int index) const {
232  return menu_items_[index].type;
233}
234
235ui::MenuSeparatorType NetworkMenuModel::GetSeparatorTypeAt(int index) const {
236  return ui::NORMAL_SEPARATOR;
237}
238
239string16 NetworkMenuModel::GetLabelAt(int index) const {
240  return menu_items_[index].label;
241}
242
243bool NetworkMenuModel::IsItemDynamicAt(int index) const {
244  return false;
245}
246
247const gfx::Font* NetworkMenuModel::GetLabelFontAt(int index) const {
248  const gfx::Font* font = NULL;
249  if (menu_items_[index].flags & FLAG_ASSOCIATED) {
250    ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance();
251    font = &resource_bundle.GetFont(
252        browser_defaults::kAssociatedNetworkFontStyle);
253  }
254
255  return font;
256}
257
258bool NetworkMenuModel::GetAcceleratorAt(int index,
259                                        ui::Accelerator* accelerator) const {
260  return false;
261}
262
263bool NetworkMenuModel::IsItemCheckedAt(int index) const {
264  // All ui::MenuModel::TYPE_CHECK menu items are checked.
265  return true;
266}
267
268int NetworkMenuModel::GetGroupIdAt(int index) const {
269  return 0;
270}
271
272bool NetworkMenuModel::GetIconAt(int index, gfx::Image* icon) {
273  if (!menu_items_[index].icon.isNull()) {
274    *icon = gfx::Image(menu_items_[index].icon);
275    return true;
276  }
277  return false;
278}
279
280ui::ButtonMenuItemModel* NetworkMenuModel::GetButtonMenuItemAt(
281    int index) const {
282  return NULL;
283}
284
285bool NetworkMenuModel::IsEnabledAt(int index) const {
286  return !(menu_items_[index].flags & FLAG_DISABLED);
287}
288
289bool NetworkMenuModel::IsVisibleAt(int index) const {
290  return true;
291}
292
293ui::MenuModel* NetworkMenuModel::GetSubmenuModelAt(int index) const {
294  return menu_items_[index].sub_menu_model;
295}
296
297void NetworkMenuModel::HighlightChangedTo(int index) {
298}
299
300void NetworkMenuModel::ActivatedAt(int index) {
301  // When we are refreshing the menu, ignore menu item activation.
302  if (owner_->refreshing_menu_)
303    return;
304
305  int flags = menu_items_[index].flags;
306  if (flags & FLAG_OPTIONS) {
307    owner_->delegate()->OpenButtonOptions();
308  } else if (flags & FLAG_TOGGLE_WIFI) {
309    ToggleTechnology(NetworkTypePattern::WiFi());
310  } else if (flags & FLAG_TOGGLE_MOBILE) {
311    ToggleTechnology(NetworkTypePattern::Mobile());
312  } else if (flags & FLAG_ETHERNET) {
313    owner_->delegate()->OnConnectToNetworkRequested(
314        menu_items_[index].service_path);
315  } else if (flags & (FLAG_WIFI | FLAG_WIMAX | FLAG_CELLULAR)) {
316    ConnectToNetworkAt(index);
317    owner_->delegate()->OnConnectToNetworkRequested(
318        menu_items_[index].service_path);
319  } else if (flags & FLAG_ADD_WIFI) {
320    ShowOther(shill::kTypeWifi);
321  } else if (flags & FLAG_ADD_CELLULAR) {
322    ShowOther(shill::kTypeCellular);
323  }
324}
325
326void NetworkMenuModel::SetMenuModelDelegate(ui::MenuModelDelegate* delegate) {
327}
328
329ui::MenuModelDelegate* NetworkMenuModel::GetMenuModelDelegate() const {
330  return NULL;
331}
332
333////////////////////////////////////////////////////////////////////////////////
334// NetworkMenuModel, private methods:
335
336void NetworkMenuModel::ShowOther(const std::string& type) const {
337  gfx::NativeWindow native_window = owner_->delegate()->GetNativeWindow();
338  if (type == shill::kTypeCellular)
339    ChooseMobileNetworkDialog::ShowDialog(native_window);
340  else
341    NetworkConfigView::ShowForType(shill::kTypeWifi, native_window);
342}
343
344////////////////////////////////////////////////////////////////////////////////
345// MainMenuModel
346
347void MainMenuModel::AddWirelessNetworkMenuItem(const NetworkState* network,
348                                               int flag) {
349  string16 label;
350  // Ampersand is a valid character in an SSID, but menu2 uses it to mark
351  // "mnemonics" for keyboard shortcuts.
352  std::string wifi_name = EscapeAmpersands(network->name());
353  if (network->IsConnectingState()) {
354    label = l10n_util::GetStringFUTF16(
355        IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
356        UTF8ToUTF16(wifi_name),
357        l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
358  } else {
359    label = UTF8ToUTF16(wifi_name);
360  }
361
362  // We do not have convenient access to whether or not it might be possible
363  // to connect to a wireless network (e.g. whether certs are required), so all
364  // entries are enabled.
365
366  if (ShouldHighlightNetwork(network))
367    flag |= FLAG_ASSOCIATED;
368  const gfx::ImageSkia icon = ash::network_icon::GetImageForNetwork(
369      network, ash::network_icon::ICON_TYPE_LIST);
370  menu_items_.push_back(
371      MenuItem(ui::MenuModel::TYPE_COMMAND,
372               label, icon, network->path(), flag));
373}
374
375void MainMenuModel::AddMessageItem(const string16& msg) {
376  menu_items_.push_back(MenuItem(
377      ui::MenuModel::TYPE_COMMAND, msg,
378      gfx::ImageSkia(), std::string(), FLAG_DISABLED));
379}
380
381void MainMenuModel::InitMenuItems(bool should_open_button_options) {
382  menu_items_.clear();
383
384  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
385
386  // Populate our MenuItems with the current list of networks.
387  string16 label;
388
389  // Ethernet
390  // Only display an ethernet icon if enabled, and an ethernet network exists.
391  bool ethernet_enabled =
392      handler->IsTechnologyEnabled(NetworkTypePattern::Ethernet());
393  const NetworkState* ethernet_network =
394      handler->FirstNetworkByType(NetworkTypePattern::Ethernet());
395  if (ethernet_enabled && ethernet_network) {
396    bool ethernet_connecting = ethernet_network->IsConnectingState();
397    if (ethernet_connecting) {
398      label = l10n_util::GetStringFUTF16(
399          IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
400          l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET),
401          l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
402    } else {
403      label = l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET);
404    }
405    int flag = FLAG_ETHERNET;
406    if (ShouldHighlightNetwork(ethernet_network))
407      flag |= FLAG_ASSOCIATED;
408    const gfx::ImageSkia icon = ash::network_icon::GetImageForNetwork(
409        ethernet_network, ash::network_icon::ICON_TYPE_LIST);
410    menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND,
411                                   label, icon, std::string(), flag));
412  }
413
414  // Get the list of all networks.
415  NetworkStateHandler::NetworkStateList network_list;
416  handler->GetNetworkList(&network_list);
417
418  // Cellular Networks
419  if (handler->IsTechnologyEnabled(NetworkTypePattern::Cellular())) {
420    // List Cellular networks.
421    for (NetworkStateHandler::NetworkStateList::const_iterator iter =
422             network_list.begin(); iter != network_list.end(); ++iter) {
423      const NetworkState* network = *iter;
424      if (network->type() != shill::kTypeCellular)
425        continue;
426      std::string activation_state = network->activation_state();
427
428      // This is only used in the login screen; do not show unactivated
429      // networks.
430      if (activation_state != shill::kActivationStateActivated)
431        continue;
432
433      // Ampersand is a valid character in a network name, but menu2 uses it
434      // to mark "mnemonics" for keyboard shortcuts.  http://crosbug.com/14697
435      std::string network_name = EscapeAmpersands(network->name());
436      if (network->IsConnectingState()) {
437        label = l10n_util::GetStringFUTF16(
438            IDS_STATUSBAR_NETWORK_DEVICE_STATUS,
439            UTF8ToUTF16(network_name),
440            l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING));
441      } else {
442        label = UTF8ToUTF16(network_name);
443      }
444
445      int flag = FLAG_CELLULAR;
446      bool isActive = ShouldHighlightNetwork(network);
447      if (isActive)
448        flag |= FLAG_ASSOCIATED;
449      const gfx::ImageSkia icon = ash::network_icon::GetImageForNetwork(
450          network, ash::network_icon::ICON_TYPE_LIST);
451      menu_items_.push_back(
452          MenuItem(ui::MenuModel::TYPE_COMMAND,
453                   label, icon, network->path(), flag));
454    }
455
456    // For GSM add cellular network scan.
457    const DeviceState* cellular_device =
458        handler->GetDeviceStateByType(NetworkTypePattern::Cellular());
459    if (cellular_device && cellular_device->support_network_scan()) {
460      const gfx::ImageSkia icon =
461          ash::network_icon::GetImageForDisconnectedNetwork(
462              ash::network_icon::ICON_TYPE_LIST, shill::kTypeCellular);
463      menu_items_.push_back(MenuItem(
464          ui::MenuModel::TYPE_COMMAND,
465          l10n_util::GetStringUTF16(
466              IDS_OPTIONS_SETTINGS_OTHER_CELLULAR_NETWORKS),
467          icon, std::string(), FLAG_ADD_CELLULAR));
468    }
469  } else {
470    int initializing_message_id =
471        ash::network_icon::GetCellularUninitializedMsg();
472    if (initializing_message_id) {
473      // Initializing cellular modem...
474      AddMessageItem(l10n_util::GetStringUTF16(initializing_message_id));
475    }
476  }
477
478  // Wimax Networks
479  if (handler->IsTechnologyEnabled(NetworkTypePattern::Wimax())) {
480    // List Wimax networks.
481    for (NetworkStateHandler::NetworkStateList::const_iterator iter =
482             network_list.begin(); iter != network_list.end(); ++iter) {
483      const NetworkState* network = *iter;
484      if (network->type() != shill::kTypeWimax)
485        continue;
486      AddWirelessNetworkMenuItem(network, FLAG_WIMAX);
487    }
488  }
489
490  // Wifi Networks
491  if (handler->IsTechnologyEnabled(NetworkTypePattern::WiFi())) {
492    // List Wifi networks.
493    int scanning_msg = handler->GetScanningByType(NetworkTypePattern::WiFi())
494                           ? IDS_ASH_STATUS_TRAY_WIFI_SCANNING_MESSAGE
495                           : 0;
496    for (NetworkStateHandler::NetworkStateList::const_iterator iter =
497             network_list.begin(); iter != network_list.end(); ++iter) {
498      const NetworkState* network = *iter;
499      if (network->type() != shill::kTypeWifi)
500        continue;
501      // Add 'Searching for Wi-Fi networks...' after connected networks.
502      if (scanning_msg && !network->IsConnectedState()) {
503        AddMessageItem(l10n_util::GetStringUTF16(scanning_msg));
504        scanning_msg = 0;
505      }
506      AddWirelessNetworkMenuItem(network, FLAG_WIFI);
507    }
508    if (scanning_msg)
509      AddMessageItem(l10n_util::GetStringUTF16(scanning_msg));
510    const gfx::ImageSkia icon =
511        ash::network_icon::GetImageForConnectedNetwork(
512            ash::network_icon::ICON_TYPE_LIST, shill::kTypeWifi);
513    menu_items_.push_back(MenuItem(
514        ui::MenuModel::TYPE_COMMAND,
515        l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_OTHER_WIFI_NETWORKS),
516        icon, std::string(), FLAG_ADD_WIFI));
517  }
518
519  if (menu_items_.empty()) {
520    // No networks available (and not initializing cellular or wifi scanning)
521    AddMessageItem(l10n_util::GetStringFUTF16(
522        IDS_STATUSBAR_NETWORK_MENU_ITEM_INDENT,
523        l10n_util::GetStringUTF16(IDS_STATUSBAR_NO_NETWORKS_MESSAGE)));
524  }
525
526  // Enable / Disable Technology
527  NetworkStateHandler::TechnologyState wifi_state =
528      handler->GetTechnologyState(NetworkTypePattern::WiFi());
529  bool wifi_available =
530      wifi_state != NetworkStateHandler::TECHNOLOGY_UNAVAILABLE;
531  bool wifi_enabled = wifi_state == NetworkStateHandler::TECHNOLOGY_ENABLED;
532
533  NetworkStateHandler::TechnologyState mobile_state =
534      handler->GetTechnologyState(NetworkTypePattern::Mobile());
535  bool mobile_available =
536      mobile_state != NetworkStateHandler::TECHNOLOGY_UNAVAILABLE;
537  bool mobile_enabled = mobile_state == NetworkStateHandler::TECHNOLOGY_ENABLED;
538
539  // Do not show disable wifi or cellular during oobe.
540  bool show_toggle_wifi = wifi_available &&
541      (should_open_button_options || !wifi_enabled);
542  bool show_toggle_mobile = mobile_available &&
543      (should_open_button_options || !mobile_enabled);
544
545  if (show_toggle_wifi || show_toggle_mobile) {
546    menu_items_.push_back(MenuItem());  // Separator
547
548    if (show_toggle_wifi) {
549      int id = wifi_enabled ? IDS_STATUSBAR_NETWORK_DEVICE_DISABLE :
550                              IDS_STATUSBAR_NETWORK_DEVICE_ENABLE;
551      label = l10n_util::GetStringFUTF16(id,
552          l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_WIFI));
553      int flag = FLAG_TOGGLE_WIFI;
554      if (wifi_state == NetworkStateHandler::TECHNOLOGY_ENABLING)
555        flag |= FLAG_DISABLED;
556      menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND, label,
557          gfx::ImageSkia(), std::string(), flag));
558    }
559
560    if (show_toggle_mobile) {
561      const DeviceState* mobile_device =
562          handler->GetDeviceStateByType(NetworkTypePattern::Mobile());
563      bool is_locked = mobile_device && !mobile_device->sim_lock_type().empty();
564      int id = (mobile_enabled && !is_locked)
565          ? IDS_STATUSBAR_NETWORK_DEVICE_DISABLE
566          : IDS_STATUSBAR_NETWORK_DEVICE_ENABLE;
567      label = l10n_util::GetStringFUTF16(id,
568          l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CELLULAR));
569      gfx::ImageSkia icon;
570      int flag = FLAG_TOGGLE_MOBILE;
571      if (mobile_state == NetworkStateHandler::TECHNOLOGY_ENABLING)
572        flag |= FLAG_DISABLED;
573      menu_items_.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND, label,
574          icon, std::string(), flag));
575    }
576  }
577
578  // Additional links like:
579  // * IP Address on active interface;
580  // * Hardware addresses for wifi and ethernet.
581  more_menu_model_->InitMenuItems(should_open_button_options);
582  if (!more_menu_model_->menu_items().empty()) {
583    menu_items_.push_back(MenuItem());  // Separator
584    menu_items_.push_back(MenuItem(
585        ui::MenuModel::TYPE_SUBMENU,
586        l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_MORE),
587        gfx::ImageSkia(), more_menu_model_.get(), FLAG_NONE));
588  }
589}
590
591int MainMenuModel::GetCommandIdAt(int index) const {
592  return index + kMainIndexMask;
593}
594
595////////////////////////////////////////////////////////////////////////////////
596// MoreMenuModel
597
598void MoreMenuModel::InitMenuItems(bool should_open_button_options) {
599  menu_items_.clear();
600  MenuItemVector link_items;
601  MenuItemVector address_items;
602
603  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
604  const NetworkState* default_network = handler->DefaultNetwork();
605
606  int message_id = -1;
607  if (default_network)
608    message_id = IDS_STATUSBAR_NETWORK_OPEN_PROXY_SETTINGS_DIALOG;
609  if (message_id != -1) {
610    link_items.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND,
611                                  l10n_util::GetStringUTF16(message_id),
612                                  gfx::ImageSkia(),
613                                  std::string(),
614                                  FLAG_OPTIONS));
615  }
616
617  if (default_network) {
618    std::string ip_address = default_network->ip_address();
619    if (!ip_address.empty()) {
620      address_items.push_back(MenuItem(ui::MenuModel::TYPE_COMMAND,
621          ASCIIToUTF16(ip_address), gfx::ImageSkia(), std::string(),
622                       FLAG_DISABLED));
623    }
624  }
625
626  std::string ethernet_address =
627      handler->FormattedHardwareAddressForType(NetworkTypePattern::Ethernet());
628  if (!ethernet_address.empty()) {
629    std::string label = l10n_util::GetStringUTF8(
630        IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET) + " " + ethernet_address;
631    address_items.push_back(MenuItem(
632        ui::MenuModel::TYPE_COMMAND,
633        UTF8ToUTF16(label), gfx::ImageSkia(), std::string(), FLAG_DISABLED));
634  }
635
636  std::string wifi_address =
637      handler->FormattedHardwareAddressForType(NetworkTypePattern::WiFi());
638  if (!wifi_address.empty()) {
639    std::string label = l10n_util::GetStringUTF8(
640        IDS_STATUSBAR_NETWORK_DEVICE_WIFI) + " " + wifi_address;
641    address_items.push_back(MenuItem(
642        ui::MenuModel::TYPE_COMMAND,
643        UTF8ToUTF16(label), gfx::ImageSkia(), std::string(), FLAG_DISABLED));
644  }
645
646  menu_items_ = link_items;
647  if (!menu_items_.empty() && address_items.size() > 1)
648    menu_items_.push_back(MenuItem());  // Separator
649  menu_items_.insert(menu_items_.end(),
650      address_items.begin(), address_items.end());
651}
652
653int MoreMenuModel::GetCommandIdAt(int index) const {
654  return index + kMoreIndexMask;
655}
656
657////////////////////////////////////////////////////////////////////////////////
658// NetworkMenu
659
660NetworkMenu::Delegate::~Delegate() {
661}
662
663NetworkMenu::NetworkMenu(Delegate* delegate)
664    : delegate_(delegate),
665      refreshing_menu_(false),
666      weak_pointer_factory_(this) {
667  main_menu_model_.reset(new MainMenuModel(weak_pointer_factory_.GetWeakPtr()));
668}
669
670NetworkMenu::~NetworkMenu() {
671}
672
673ui::MenuModel* NetworkMenu::GetMenuModel() {
674  return main_menu_model_.get();
675}
676
677void NetworkMenu::UpdateMenu() {
678  refreshing_menu_ = true;
679  main_menu_model_->InitMenuItems(delegate_->ShouldOpenButtonOptions());
680  refreshing_menu_ = false;
681}
682
683}  // namespace chromeos
684