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/ui/webui/chromeos/login/network_dropdown.h"
6
7#include <string>
8
9#include "ash/system/chromeos/network/network_icon.h"
10#include "ash/system/chromeos/network/network_icon_animation.h"
11#include "base/time/time.h"
12#include "base/values.h"
13#include "chrome/browser/chromeos/login/login_display_host.h"
14#include "chrome/browser/chromeos/login/login_display_host_impl.h"
15#include "chromeos/network/network_state_handler.h"
16#include "content/public/browser/web_ui.h"
17#include "ui/base/models/menu_model.h"
18#include "ui/gfx/font.h"
19#include "ui/gfx/image/image.h"
20#include "ui/gfx/image/image_skia.h"
21#include "ui/webui/web_ui_util.h"
22
23namespace {
24
25// Timeout between consecutive requests to network library for network
26// scan.
27const int kNetworkScanIntervalSecs = 60;
28
29}  // namespace
30
31namespace chromeos {
32
33// WebUI specific implementation of the NetworkMenu class.
34class NetworkMenuWebUI : public NetworkMenu {
35 public:
36  NetworkMenuWebUI(NetworkMenu::Delegate* delegate, content::WebUI* web_ui);
37
38  // NetworkMenu override:
39  virtual void UpdateMenu() OVERRIDE;
40
41  // Called when item with command |id| is chosen.
42  void OnItemChosen(int id);
43
44 private:
45  // Converts menu model into the ListValue, ready for passing to WebUI.
46  base::ListValue* ConvertMenuModel(ui::MenuModel* model);
47
48  // WebUI where network menu is located.
49  content::WebUI* web_ui_;
50
51  DISALLOW_COPY_AND_ASSIGN(NetworkMenuWebUI);
52};
53
54// NetworkMenuWebUI ------------------------------------------------------------
55
56NetworkMenuWebUI::NetworkMenuWebUI(NetworkMenu::Delegate* delegate,
57                                   content::WebUI* web_ui)
58    : NetworkMenu(delegate),
59      web_ui_(web_ui) {
60}
61
62void NetworkMenuWebUI::UpdateMenu() {
63  NetworkMenu::UpdateMenu();
64  if (web_ui_) {
65    scoped_ptr<base::ListValue> list(ConvertMenuModel(GetMenuModel()));
66    web_ui_->CallJavascriptFunction("cr.ui.DropDown.updateNetworks", *list);
67  }
68}
69
70void NetworkMenuWebUI::OnItemChosen(int id) {
71  int index;
72  ui::MenuModel* model = GetMenuModel();
73   if (!ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index))
74     return;
75  model->ActivatedAt(index);
76}
77
78base::ListValue* NetworkMenuWebUI::ConvertMenuModel(ui::MenuModel* model) {
79  base::ListValue* list = new base::ListValue();
80  for (int i = 0; i < model->GetItemCount(); ++i) {
81    ui::MenuModel::ItemType type = model->GetTypeAt(i);
82    int id;
83    if (type == ui::MenuModel::TYPE_SEPARATOR)
84      id = -2;
85    else
86      id = model->GetCommandIdAt(i);
87    base::DictionaryValue* item = new base::DictionaryValue();
88    item->SetInteger("id", id);
89    item->SetString("label", model->GetLabelAt(i));
90    gfx::Image icon;
91    if (model->GetIconAt(i, &icon)) {
92      SkBitmap icon_bitmap = icon.ToImageSkia()->GetRepresentation(
93          web_ui_->GetDeviceScaleFactor()).sk_bitmap();
94      item->SetString("icon", webui::GetBitmapDataUrl(icon_bitmap));
95    }
96    if (id >= 0) {
97      item->SetBoolean("enabled", model->IsEnabledAt(i));
98      const gfx::Font* font = model->GetLabelFontAt(i);
99      if (font) {
100        item->SetBoolean("bold", font->GetStyle() == gfx::Font::BOLD);
101      }
102    }
103    if (type == ui::MenuModel::TYPE_SUBMENU)
104      item->Set("sub", ConvertMenuModel(model->GetSubmenuModelAt(i)));
105    list->Append(item);
106  }
107  return list;
108}
109
110// NetworkDropdown -------------------------------------------------------------
111
112NetworkDropdown::NetworkDropdown(Actor* actor,
113                                 content::WebUI* web_ui,
114                                 bool oobe)
115    : actor_(actor),
116      web_ui_(web_ui),
117      oobe_(oobe) {
118  DCHECK(actor_);
119  network_menu_.reset(new NetworkMenuWebUI(this, web_ui));
120  DCHECK(NetworkHandler::IsInitialized());
121  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
122  handler->RequestScan();
123  handler->AddObserver(this, FROM_HERE);
124  Refresh();
125  network_scan_timer_.Start(
126      FROM_HERE,
127      base::TimeDelta::FromSeconds(kNetworkScanIntervalSecs),
128      this, &NetworkDropdown::RequestNetworkScan);
129}
130
131NetworkDropdown::~NetworkDropdown() {
132  ash::network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
133  if (NetworkHandler::IsInitialized()) {
134    NetworkHandler::Get()->network_state_handler()->RemoveObserver(
135        this, FROM_HERE);
136  }
137}
138
139void NetworkDropdown::OnItemChosen(int id) {
140  network_menu_->OnItemChosen(id);
141}
142
143gfx::NativeWindow NetworkDropdown::GetNativeWindow() const {
144  return LoginDisplayHostImpl::default_host()->GetNativeWindow();
145}
146
147void NetworkDropdown::OpenButtonOptions() {
148  LoginDisplayHostImpl::default_host()->OpenProxySettings();
149}
150
151bool NetworkDropdown::ShouldOpenButtonOptions() const {
152  return !oobe_;
153}
154
155void NetworkDropdown::OnConnectToNetworkRequested(
156    const std::string& service_path) {
157  actor_->OnConnectToNetworkRequested(service_path);
158}
159
160void NetworkDropdown::DefaultNetworkChanged(const NetworkState* network) {
161  Refresh();
162}
163
164void NetworkDropdown::NetworkConnectionStateChanged(
165    const NetworkState* network) {
166  Refresh();
167}
168
169void NetworkDropdown::NetworkListChanged() {
170  Refresh();
171}
172
173void NetworkDropdown::NetworkIconChanged() {
174  SetNetworkIconAndText();
175}
176
177void NetworkDropdown::Refresh() {
178  SetNetworkIconAndText();
179  network_menu_->UpdateMenu();
180}
181
182void NetworkDropdown::SetNetworkIconAndText() {
183  string16 text;
184  gfx::ImageSkia icon_image;
185  bool animating = false;
186  ash::network_icon::GetDefaultNetworkImageAndLabel(
187      ash::network_icon::ICON_TYPE_LIST, &icon_image, &text, &animating);
188  if (animating) {
189    ash::network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this);
190  } else {
191    ash::network_icon::NetworkIconAnimation::GetInstance()->
192        RemoveObserver(this);
193  }
194  SkBitmap icon_bitmap = icon_image.GetRepresentation(
195      web_ui_->GetDeviceScaleFactor()).sk_bitmap();
196  std::string icon_str;
197  if (!icon_image.isNull())
198    icon_str = webui::GetBitmapDataUrl(icon_bitmap);
199  base::StringValue title(text);
200  base::StringValue icon(icon_str);
201  web_ui_->CallJavascriptFunction("cr.ui.DropDown.updateNetworkTitle",
202                                  title, icon);
203}
204
205void NetworkDropdown::RequestNetworkScan() {
206  NetworkHandler::Get()->network_state_handler()->RequestScan();
207  Refresh();
208}
209
210}  // namespace chromeos
211