Chromium Code Reviews| Index: chrome/browser/chromeos/status/network_menu.cc |
| diff --git a/chrome/browser/chromeos/status/network_menu.cc b/chrome/browser/chromeos/status/network_menu.cc |
| index c87bfa7c04830dbe73b6f1827e6ba2a0ac29887b..3e071c3374c957194c1dbf3b470e12ca5ada3473 100644 |
| --- a/chrome/browser/chromeos/status/network_menu.cc |
| +++ b/chrome/browser/chromeos/status/network_menu.cc |
| @@ -26,7 +26,8 @@ |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/gfx/canvas_skia.h" |
| #include "ui/gfx/skbitmap_operations.h" |
| -#include "views/controls/menu/menu_2.h" |
| +#include "views/controls/menu/menu_item_view.h" |
| +#include "views/controls/menu/submenu_view.h" |
| #include "views/window/window.h" |
| namespace { |
| @@ -42,10 +43,155 @@ std::string EscapeAmpersands(const std::string& input) { |
| return str; |
| } |
| +// Offsets for views menu ids (main menu and submenu ids use the same |
| +// namespace). |
| +const int kMainIndexOffset = 1000; |
| +const int kVPNIndexOffset = 2000; |
| +const int kMoreIndexOffset = 3000; |
| + |
| +// Default minimum width in pixels of the menu to prevent unnecessary |
| +// resizing as networks are updated. |
| +const int kDefaultMinimumWidth = 280; |
| + |
| } // namespace |
| namespace chromeos { |
| +class NetworkMenuModel : public views::MenuDelegate { |
| + public: |
| + struct NetworkInfo { |
| + NetworkInfo(); |
| + ~NetworkInfo(); |
| + |
| + // "ethernet" | "wifi" | "cellular" | "other". |
| + std::string network_type; |
| + // "connected" | "connecting" | "disconnected" | "error". |
| + std::string status; |
| + // status message or error message, empty if unknown status. |
| + std::string message; |
| + // IP address (if network is active, empty otherwise) |
| + std::string ip_address; |
| + // Remembered passphrase. |
| + std::string passphrase; |
| + // true if the network requires a passphrase. |
| + bool need_passphrase; |
| + // true if the network is currently remembered. |
| + bool remembered; |
| + // true if the network is auto connect (meaningful for Wifi only). |
| + bool auto_connect; |
| + }; |
| + |
| + explicit NetworkMenuModel(NetworkMenu* owner); |
| + virtual ~NetworkMenuModel(); |
| + |
| + // Connect or reconnect to the network at |index|. |
| + // If remember >= 0, set the favorite state of the network. |
| + // Returns true if a connect occurred (e.g. menu should be closed). |
| + bool ConnectToNetworkAt(int index, |
|
stevenjb
2011/05/18 17:36:15
I don't believe the return value for this is used
rhashimoto
2011/05/18 18:15:45
Done.
|
| + const std::string& passphrase, |
| + const std::string& ssid, |
| + int remember) const; |
| + |
| + // Called by NetworkMenu::RunMenu to initialize list of menu items. |
| + virtual void InitMenuItems(bool is_browser_mode, |
| + bool should_open_button_options) = 0; |
| + |
| + // PopulateMenu() clears and reinstalls the menu items defined in this |
| + // instance by calling PopulateMenuItem() on each one. Subclasses override |
| + // PopulateMenuItem(), transform command_id into the correct range for |
| + // the menu, and call the base class PopulateMenuItem(). |
| + virtual void PopulateMenu(views::MenuItemView* menu); |
| + virtual void PopulateMenuItem( |
| + views::MenuItemView* menu, |
| + int index, |
| + int command_id); |
| + |
| + // Menu item field accessors. |
| + int GetItemCount() const; |
| + ui::MenuModel::ItemType GetTypeAt(int index) const; |
| + string16 GetLabelAt(int index) const; |
| + const gfx::Font* GetLabelFontAt(int index) const; |
| + bool IsItemCheckedAt(int index) const; |
| + bool GetIconAt(int index, SkBitmap* icon); |
| + bool IsEnabledAt(int index) const; |
| + NetworkMenuModel* GetSubmenuModelAt(int index) const; |
| + void ActivatedAt(int index); |
| + |
| + protected: |
| + enum MenuItemFlags { |
| + FLAG_NONE = 0, |
| + FLAG_DISABLED = 1 << 0, |
| + FLAG_TOGGLE_ETHERNET = 1 << 1, |
| + FLAG_TOGGLE_WIFI = 1 << 2, |
| + FLAG_TOGGLE_CELLULAR = 1 << 3, |
| + FLAG_TOGGLE_OFFLINE = 1 << 4, |
| + FLAG_ASSOCIATED = 1 << 5, |
| + FLAG_ETHERNET = 1 << 6, |
| + FLAG_WIFI = 1 << 7, |
| + FLAG_CELLULAR = 1 << 8, |
| + FLAG_OPTIONS = 1 << 9, |
| + FLAG_ADD_WIFI = 1 << 10, |
| + FLAG_ADD_CELLULAR = 1 << 11, |
| + FLAG_VPN = 1 << 12, |
| + FLAG_ADD_VPN = 1 << 13, |
| + FLAG_DISCONNECT_VPN = 1 << 14, |
| + FLAG_VIEW_ACCOUNT = 1 << 15, |
| + }; |
| + |
| + struct MenuItem { |
| + MenuItem() |
| + : type(ui::MenuModel::TYPE_SEPARATOR), |
| + sub_menu_model(NULL), |
| + flags(0) {} |
| + MenuItem(ui::MenuModel::ItemType type, string16 label, SkBitmap icon, |
| + const std::string& service_path, int flags) |
| + : type(type), |
| + label(label), |
| + icon(icon), |
| + service_path(service_path), |
| + sub_menu_model(NULL), |
| + flags(flags) {} |
| + MenuItem(ui::MenuModel::ItemType type, string16 label, SkBitmap icon, |
| + NetworkMenuModel* sub_menu_model, int flags) |
| + : type(type), |
| + label(label), |
| + icon(icon), |
| + sub_menu_model(sub_menu_model), |
| + flags(flags) {} |
| + |
| + ui::MenuModel::ItemType type; |
| + string16 label; |
| + SkBitmap icon; |
| + std::string service_path; |
| + NetworkMenuModel* sub_menu_model; // Weak. |
| + int flags; |
| + }; |
| + typedef std::vector<MenuItem> MenuItemVector; |
| + |
| + // Our menu items. |
| + MenuItemVector menu_items_; |
| + |
| + NetworkMenu* owner_; // Weak pointer to NetworkMenu that owns this MenuModel. |
| + |
| + // Top up URL of the current carrier on empty string if there's none. |
| + std::string top_up_url_; |
| + |
| + // Carrier ID which top up URL is initialized for. |
| + // Used to update top up URL only when cellular carrier has changed. |
| + std::string carrier_id_; |
| + |
| + private: |
| + // Show a NetworkConfigView modal dialog instance. |
| + void ShowNetworkConfigView(NetworkConfigView* view) const; |
| + |
| + void ActivateCellular(const CellularNetwork* cellular) const; |
| + void ShowOther(ConnectionType type) const; |
| + void ShowOtherCellular() const; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(NetworkMenuModel); |
| +}; |
| + |
| + |
| class MoreMenuModel : public NetworkMenuModel { |
| public: |
| explicit MoreMenuModel(NetworkMenu* owner); |
| @@ -53,7 +199,11 @@ class MoreMenuModel : public NetworkMenuModel { |
| // NetworkMenuModel implementation. |
| virtual void InitMenuItems(bool is_browser_mode, |
| - bool should_open_button_options); |
| + bool should_open_button_options) OVERRIDE; |
| + virtual void PopulateMenuItem( |
| + views::MenuItemView* menu, |
| + int index, |
| + int command_id) OVERRIDE; |
|
stevenjb
2011/05/18 17:36:15
nit: use same indentation style for above function
rhashimoto
2011/05/18 18:15:45
Done.
|
| private: |
| friend class MainMenuModel; |
| @@ -67,7 +217,11 @@ class VPNMenuModel : public NetworkMenuModel { |
| // NetworkMenuModel implementation. |
| virtual void InitMenuItems(bool is_browser_mode, |
| - bool should_open_button_options); |
| + bool should_open_button_options) OVERRIDE; |
| + virtual void PopulateMenuItem( |
| + views::MenuItemView* menu, |
| + int index, |
| + int command_id) OVERRIDE; |
|
stevenjb
2011/05/18 17:36:15
nit: use same indentation style for above function
rhashimoto
2011/05/18 18:15:45
Done.
|
| static SkBitmap IconForDisplay(const Network* network); |
| @@ -82,7 +236,17 @@ class MainMenuModel : public NetworkMenuModel { |
| // NetworkMenuModel implementation. |
| virtual void InitMenuItems(bool is_browser_mode, |
| - bool should_open_button_options); |
| + bool should_open_button_options) OVERRIDE; |
| + virtual void PopulateMenuItem( |
| + views::MenuItemView* menu, |
| + int index, |
| + int command_id) OVERRIDE; |
|
stevenjb
2011/05/18 17:36:15
nit: use same indentation style for above function
rhashimoto
2011/05/18 18:15:45
Done.
|
| + |
| + // views::MenuDelegate implementation. |
| + virtual const gfx::Font& GetLabelFont(int id) const OVERRIDE; |
| + virtual bool IsItemChecked(int id) const OVERRIDE; |
| + virtual bool IsCommandEnabled(int id) const OVERRIDE; |
| + virtual void ExecuteCommand(int id) OVERRIDE; |
| private: |
| scoped_ptr<NetworkMenuModel> vpn_menu_model_; |
| @@ -107,6 +271,57 @@ NetworkMenuModel::NetworkMenuModel(NetworkMenu* owner) : owner_(owner) {} |
| NetworkMenuModel::~NetworkMenuModel() {} |
| +void NetworkMenuModel::PopulateMenu(views::MenuItemView* menu) { |
| + const int old_count = menu->CreateSubmenu()->child_count(); |
|
stevenjb
2011/05/18 17:36:15
CreateSubmenu() here is confusing since we are jus
rhashimoto
2011/05/18 18:15:45
Done.
|
| + for (int i = 0; i < old_count; ++i) |
| + menu->RemoveMenuItemAt(0); |
| + |
| + const int menu_items_count = GetItemCount(); |
| + for (int i = 0; i < menu_items_count; ++i) |
| + PopulateMenuItem(menu, i, i); |
| +} |
| + |
| +void NetworkMenuModel::PopulateMenuItem( |
| + views::MenuItemView* menu, |
| + int index, |
| + int command_id) { |
| + DCHECK_GT(GetItemCount(), index); |
| + switch (GetTypeAt(index)) { |
| + case ui::MenuModel::TYPE_SEPARATOR: |
| + menu->AppendSeparator(); |
| + break; |
| + case ui::MenuModel::TYPE_COMMAND: { |
| + SkBitmap icon; |
| + if (GetIconAt(index, &icon)) { |
| + menu->AppendMenuItemWithIcon( |
| + command_id, |
| + UTF16ToWide(GetLabelAt(index)), |
| + icon); |
| + } else { |
| + menu->AppendMenuItemWithLabel(command_id, |
| + UTF16ToWide(GetLabelAt(index))); |
| + } |
|
stevenjb
2011/05/18 17:36:15
nit: use same indentation style for each if clause
rhashimoto
2011/05/18 18:15:45
Done.
|
| + break; |
| + } |
| + case ui::MenuModel::TYPE_SUBMENU: { |
| + views::MenuItemView* submenu = NULL; |
| + SkBitmap icon; |
| + if (GetIconAt(index, &icon)) { |
| + submenu = menu->AppendSubMenuWithIcon(command_id, |
| + UTF16ToWide(GetLabelAt(index)), |
| + icon); |
| + } else { |
| + submenu = menu->AppendSubMenu(command_id, |
| + UTF16ToWide(GetLabelAt(index))); |
| + } |
| + GetSubmenuModelAt(index)->PopulateMenu(submenu); |
| + break; |
| + } |
| + default: |
| + NOTREACHED(); |
| + } |
| +} |
| + |
| bool NetworkMenuModel::ConnectToNetworkAt(int index, |
| const std::string& passphrase, |
| const std::string& ssid, |
| @@ -204,10 +419,6 @@ bool NetworkMenuModel::ConnectToNetworkAt(int index, |
| //////////////////////////////////////////////////////////////////////////////// |
| // NetworkMenuModel, ui::MenuModel implementation: |
| -bool NetworkMenuModel::HasIcons() const { |
| - return true; |
| -} |
| - |
| int NetworkMenuModel::GetItemCount() const { |
| return static_cast<int>(menu_items_.size()); |
| } |
| @@ -216,38 +427,21 @@ ui::MenuModel::ItemType NetworkMenuModel::GetTypeAt(int index) const { |
| return menu_items_[index].type; |
| } |
| -int NetworkMenuModel::GetCommandIdAt(int index) const { |
| - return index; |
| -} |
| - |
| string16 NetworkMenuModel::GetLabelAt(int index) const { |
| return menu_items_[index].label; |
| } |
| -bool NetworkMenuModel::IsItemDynamicAt(int index) const { |
| - return true; |
| -} |
| - |
| const gfx::Font* NetworkMenuModel::GetLabelFontAt(int index) const { |
| return (menu_items_[index].flags & FLAG_ASSOCIATED) ? |
| &ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BoldFont) : |
| NULL; |
| } |
| -bool NetworkMenuModel::GetAcceleratorAt( |
| - int index, ui::Accelerator* accelerator) const { |
| - return false; |
| -} |
| - |
| bool NetworkMenuModel::IsItemCheckedAt(int index) const { |
| // All ui::MenuModel::TYPE_CHECK menu items are checked. |
| return true; |
| } |
| -int NetworkMenuModel::GetGroupIdAt(int index) const { |
| - return 0; |
| -} |
| - |
| bool NetworkMenuModel::GetIconAt(int index, SkBitmap* icon) { |
| if (!menu_items_[index].icon.empty()) { |
| *icon = menu_items_[index].icon; |
| @@ -256,21 +450,14 @@ bool NetworkMenuModel::GetIconAt(int index, SkBitmap* icon) { |
| return false; |
| } |
| -ui::ButtonMenuItemModel* NetworkMenuModel::GetButtonMenuItemAt( |
| - int index) const { |
| - return NULL; |
| -} |
| - |
| bool NetworkMenuModel::IsEnabledAt(int index) const { |
| return !(menu_items_[index].flags & FLAG_DISABLED); |
| } |
| -ui::MenuModel* NetworkMenuModel::GetSubmenuModelAt(int index) const { |
| +NetworkMenuModel* NetworkMenuModel::GetSubmenuModelAt(int index) const { |
| return menu_items_[index].sub_menu_model; |
| } |
| -void NetworkMenuModel::HighlightChangedTo(int index) {} |
| - |
| void NetworkMenuModel::ActivatedAt(int index) { |
| // When we are refreshing the menu, ignore menu item activation. |
| if (owner_->refreshing_menu_) |
| @@ -319,10 +506,6 @@ void NetworkMenuModel::ActivatedAt(int index) { |
| } |
| } |
| -void NetworkMenuModel::MenuWillShow() {} |
| - |
| -void NetworkMenuModel::SetMenuModelDelegate(ui::MenuModelDelegate* delegate) {} |
| - |
| //////////////////////////////////////////////////////////////////////////////// |
| // NetworkMenuModel, private methods: |
| @@ -690,6 +873,68 @@ void MainMenuModel::InitMenuItems(bool is_browser_mode, |
| } |
| } |
| +void MainMenuModel::PopulateMenuItem( |
| + views::MenuItemView* menu, |
| + int index, |
| + int command_id) { |
| + NetworkMenuModel::PopulateMenuItem(menu, index, |
| + command_id + kMainIndexOffset); |
| +} |
| + |
| +// views::MenuDelegate implementation. |
| + |
| +const gfx::Font& MainMenuModel::GetLabelFont(int id) const { |
| + DCHECK_GT(kMoreIndexOffset, kVPNIndexOffset); |
| + DCHECK_GT(kVPNIndexOffset, kMainIndexOffset); |
| + const gfx::Font* font = NULL; |
| + if (id >= kMoreIndexOffset) |
| + font = more_menu_model_->GetLabelFontAt(id - kMoreIndexOffset); |
| + else if (id >= kVPNIndexOffset) |
| + font = vpn_menu_model_->GetLabelFontAt(id - kVPNIndexOffset); |
| + else if (id >= kMainIndexOffset) |
| + font = GetLabelFontAt(id - kMainIndexOffset); |
| + |
| + return font ? *font: views::MenuDelegate::GetLabelFont(id); |
|
stevenjb
2011/05/18 17:36:15
nit: ' ' after * and before :
rhashimoto
2011/05/18 18:15:45
Done.
|
| +} |
| + |
| + |
| +bool MainMenuModel::IsItemChecked(int id) const { |
| + DCHECK_GT(kMoreIndexOffset, kVPNIndexOffset); |
| + DCHECK_GT(kVPNIndexOffset, kMainIndexOffset); |
| + if (id >= kMoreIndexOffset) |
| + return more_menu_model_->IsItemCheckedAt(id - kMoreIndexOffset); |
| + else if (id >= kVPNIndexOffset) |
| + return vpn_menu_model_->IsItemCheckedAt(id - kVPNIndexOffset); |
| + else if (id >= kMainIndexOffset) |
| + return IsItemCheckedAt(id - kMainIndexOffset); |
| + |
| + return views::MenuDelegate::IsItemChecked(id); |
| +} |
| + |
| +bool MainMenuModel::IsCommandEnabled(int id) const { |
| + DCHECK_GT(kMoreIndexOffset, kVPNIndexOffset); |
| + DCHECK_GT(kVPNIndexOffset, kMainIndexOffset); |
| + if (id >= kMoreIndexOffset) |
| + return more_menu_model_->IsEnabledAt(id - kMoreIndexOffset); |
| + else if (id >= kVPNIndexOffset) |
| + return vpn_menu_model_->IsEnabledAt(id - kVPNIndexOffset); |
| + else if (id >= kMainIndexOffset) |
| + return IsEnabledAt(id - kMainIndexOffset); |
| + |
| + return views::MenuDelegate::IsCommandEnabled(id); |
| +} |
| + |
| +void MainMenuModel::ExecuteCommand(int id) { |
| + DCHECK_GT(kMoreIndexOffset, kVPNIndexOffset); |
| + DCHECK_GT(kVPNIndexOffset, kMainIndexOffset); |
| + if (id >= kMoreIndexOffset) |
| + more_menu_model_->ActivatedAt(id - kMoreIndexOffset); |
| + else if (id >= kVPNIndexOffset) |
| + vpn_menu_model_->ActivatedAt(id - kVPNIndexOffset); |
| + else if (id >= kMainIndexOffset) |
| + ActivatedAt(id - kMainIndexOffset); |
| +} |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| // VPNMenuModel |
| @@ -762,6 +1007,14 @@ void VPNMenuModel::InitMenuItems(bool is_browser_mode, |
| } |
| } |
| +void VPNMenuModel::PopulateMenuItem( |
| + views::MenuItemView* menu, |
| + int index, |
| + int command_id) { |
| + NetworkMenuModel::PopulateMenuItem(menu, index, |
| + command_id + kVPNIndexOffset); |
| +} |
| + |
| // static |
| SkBitmap VPNMenuModel::IconForDisplay(const Network* network) { |
| ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| @@ -871,6 +1124,14 @@ void MoreMenuModel::InitMenuItems( |
| address_items.begin(), address_items.end()); |
| } |
| +void MoreMenuModel::PopulateMenuItem( |
| + views::MenuItemView* menu, |
| + int index, |
| + int command_id) { |
| + NetworkMenuModel::PopulateMenuItem(menu, index, |
| + command_id + kMoreIndexOffset); |
| +} |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| // NetworkMenu |
| @@ -920,9 +1181,10 @@ SkBitmap NetworkMenu::kAnimatingImages[kNumAnimatingImages]; |
| // static |
| SkBitmap NetworkMenu::kAnimatingImagesBlack[kNumAnimatingImages]; |
| -NetworkMenu::NetworkMenu() : min_width_(-1) { |
| +NetworkMenu::NetworkMenu() : min_width_(kDefaultMinimumWidth) { |
| main_menu_model_.reset(new MainMenuModel(this)); |
| - network_menu_.reset(new views::Menu2(main_menu_model_.get())); |
| + network_menu_.reset(new views::MenuItemView(main_menu_model_.get())); |
| + network_menu_->set_has_icons(true); |
| } |
| NetworkMenu::~NetworkMenu() { |
| @@ -930,18 +1192,17 @@ NetworkMenu::~NetworkMenu() { |
| void NetworkMenu::SetFirstLevelMenuWidth(int width) { |
| min_width_ = width; |
| - // This actually has no effect since menu is rebuilt before showing. |
| - network_menu_->SetMinimumWidth(width); |
| } |
| void NetworkMenu::CancelMenu() { |
| - network_menu_->CancelMenu(); |
| + network_menu_->Cancel(); |
| } |
| void NetworkMenu::UpdateMenu() { |
| refreshing_menu_ = true; |
| main_menu_model_->InitMenuItems(IsBrowserMode(), ShouldOpenButtonOptions()); |
| - network_menu_->Rebuild(); |
| + main_menu_model_->PopulateMenu(network_menu_.get()); |
| + network_menu_->ChildrenChanged(); |
| refreshing_menu_ = false; |
| } |
| @@ -1156,24 +1417,26 @@ void NetworkMenu::ShowTabbedNetworkSettings(const Network* network) const { |
| // NetworkMenu, views::ViewMenuDelegate implementation: |
| void NetworkMenu::RunMenu(views::View* source, const gfx::Point& pt) { |
| - refreshing_menu_ = true; |
| NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); |
| cros->RequestNetworkScan(); |
| - // Build initial menu items. They will be updated when UpdateMenu is |
| - // called from NetworkChanged. |
| - main_menu_model_->InitMenuItems(IsBrowserMode(), ShouldOpenButtonOptions()); |
| - network_menu_->Rebuild(); |
| - |
| - // Restore menu width, if it was set up. |
| - // NOTE: width isn't checked for correctness here since all width-related |
| - // logic implemented inside |network_menu_|. |
| - if (min_width_ != -1) |
| - network_menu_->SetMinimumWidth(min_width_); |
| - refreshing_menu_ = false; |
| - network_menu_->RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT); |
| + UpdateMenu(); |
| + |
| + // TODO(rhashimoto): Remove this workaround when WebUI provides a |
| + // top-level widget on the ChromeOS login screen that is a window. |
| + // The current BackgroundView class for the ChromeOS login screen |
| + // creates a owning Widget that has a native GtkWindow but is not a |
| + // Window. This makes it impossible to get the NativeWindow via |
| + // the views API. This workaround casts the top-level NativeWidget |
| + // to a NativeWindow that we can pass to MenuItemView::RunMenuAt(). |
| + gfx::NativeWindow window = GTK_WINDOW(source->GetWidget()->GetNativeView()); |
| + |
| + gfx::Point screen_loc; |
| + views::View::ConvertPointToScreen(source, &screen_loc); |
| + gfx::Rect bounds(screen_loc, source->size()); |
| + network_menu_->GetSubmenu()->set_minimum_preferred_width(min_width_); |
| + network_menu_->RunMenuAt(window, GetMenuButton(), bounds, |
| + views::MenuItemView::TOPRIGHT, true); |
| } |
| } // namespace chromeos |
| - |
| - |