OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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/webui/menu_ui.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/callback.h" | |
10 #include "base/command_line.h" | |
11 #include "base/json/json_writer.h" | |
12 #include "base/message_loop.h" | |
13 #include "base/singleton.h" | |
14 #include "base/string_number_conversions.h" | |
15 #include "base/string_piece.h" | |
16 #include "base/utf_string_conversions.h" | |
17 #include "base/values.h" | |
18 #include "base/weak_ptr.h" | |
19 #include "chrome/browser/chromeos/views/native_menu_webui.h" | |
20 #include "chrome/browser/chromeos/views/webui_menu_widget.h" | |
21 #include "chrome/browser/profiles/profile.h" | |
22 #include "chrome/common/chrome_switches.h" | |
23 #include "chrome/common/jstemplate_builder.h" | |
24 #include "chrome/common/url_constants.h" | |
25 #include "content/browser/browser_thread.h" | |
26 #include "content/browser/tab_contents/tab_contents.h" | |
27 #include "content/browser/tab_contents/tab_contents_delegate.h" | |
28 #include "content/browser/webui/web_ui_util.h" | |
29 #include "grit/app_resources.h" | |
30 #include "grit/browser_resources.h" | |
31 #include "ui/base/models/menu_model.h" | |
32 #include "ui/base/resource/resource_bundle.h" | |
33 #include "ui/gfx/canvas_skia.h" | |
34 #include "ui/gfx/favicon_size.h" | |
35 #include "ui/gfx/font.h" | |
36 #include "views/accelerator.h" | |
37 #include "views/controls/menu/menu_config.h" | |
38 #include "views/controls/menu/menu_image_util_gtk.h" | |
39 #include "views/widget/widget_gtk.h" | |
40 | |
41 namespace { | |
42 | |
43 // a fake resource id for not loading extra resource. | |
44 const int kNoExtraResource = -1; | |
45 | |
46 // A utility function that generates css font property from gfx::Font. | |
47 // NOTE: Returns UTF-8. | |
48 std::string GetFontShorthand(const gfx::Font* font) { | |
49 std::string out; | |
50 if (font == NULL) { | |
51 font = &(views::MenuConfig::instance().font); | |
52 } | |
53 if (font->GetStyle() & gfx::Font::BOLD) { | |
54 out.append("bold "); | |
55 } | |
56 if (font->GetStyle() & gfx::Font::ITALIC) { | |
57 out.append("italic "); | |
58 } | |
59 if (font->GetStyle() & gfx::Font::UNDERLINED) { | |
60 out.append("underline "); | |
61 } | |
62 | |
63 // TODO(oshima): The font size from gfx::Font is too small when | |
64 // used in webkit. Figure out the reason. | |
65 out.append(base::IntToString(font->GetFontSize() + 4)); | |
66 out.append("px/"); | |
67 out.append(base::IntToString(std::max(kFaviconSize, font->GetHeight()))); | |
68 out.append("px \""); | |
69 out.append(UTF16ToUTF8(font->GetFontName())); | |
70 out.append("\",sans-serif"); | |
71 return out; | |
72 } | |
73 | |
74 // Creates scroll button's up image when |up| is true or | |
75 // down image if |up| is false. | |
76 SkBitmap CreateMenuScrollArrowImage(bool up) { | |
77 const views::MenuConfig& config = views::MenuConfig::instance(); | |
78 | |
79 int height = config.scroll_arrow_height; | |
80 gfx::CanvasSkia canvas(height * 2, height, false); | |
81 | |
82 if (!up) { | |
83 // flip the direction. | |
84 canvas.scale(1.0, -1.0); | |
85 canvas.translate(0, -height); | |
86 } | |
87 // Draw triangle. | |
88 SkPath path; | |
89 path.moveTo(height, 0); | |
90 path.lineTo(0, height); | |
91 path.lineTo(height * 2, height); | |
92 SkPaint paint; | |
93 paint.setColor(SK_ColorBLACK); | |
94 paint.setStyle(SkPaint::kFill_Style); | |
95 paint.setAntiAlias(true); | |
96 canvas.drawPath(path, paint); | |
97 return canvas.ExtractBitmap(); | |
98 } | |
99 | |
100 // Returns the scroll button's up image if |up| is true, or | |
101 // "down" image otherwise. | |
102 const std::string& GetImageDataUrlForMenuScrollArrow(bool up) { | |
103 static const std::string upImage = | |
104 web_ui_util::GetImageDataUrl(CreateMenuScrollArrowImage(true)); | |
105 static const std::string downImage = | |
106 web_ui_util::GetImageDataUrl(CreateMenuScrollArrowImage(false)); | |
107 return up ? upImage : downImage; | |
108 } | |
109 | |
110 // Returns the radio button's "on" image if |on| is true, or | |
111 // "off" image otherwise. | |
112 const std::string& GetImageDataUrlForRadio(bool on) { | |
113 static const std::string onImage = | |
114 web_ui_util::GetImageDataUrl(*views::GetRadioButtonImage(true)); | |
115 static const std::string offImage = | |
116 web_ui_util::GetImageDataUrl(*views::GetRadioButtonImage(false)); | |
117 return on ? onImage : offImage; | |
118 } | |
119 | |
120 /** | |
121 * Generates a html file that uses |menu_class| as a menu implementation. | |
122 * |menu_source_id| specifies the source that contains the definition of the | |
123 * |menu_class|, or empty string to use plain "Menu". | |
124 * | |
125 * TODO(oshima): make this template to avoid repeatedly loading the | |
126 * same source/css files. | |
127 */ | |
128 std::string GetMenuUIHTMLSourceFromString( | |
129 const chromeos::MenuSourceDelegate* delegate, | |
130 const base::StringPiece& menu_template, | |
131 const std::string& menu_class, | |
132 int menu_source_id, | |
133 int menu_css_id) { | |
134 #define SET_INTEGER_PROPERTY(prop) \ | |
135 value_config.SetInteger(#prop, menu_config.prop) | |
136 | |
137 const views::MenuConfig& menu_config = views::MenuConfig::instance(); | |
138 | |
139 DictionaryValue value_config; | |
140 value_config.SetString("radioOnUrl", GetImageDataUrlForRadio(true)); | |
141 value_config.SetString("radioOffUrl", GetImageDataUrlForRadio(false)); | |
142 value_config.SetString( | |
143 "arrowUrl", web_ui_util::GetImageDataUrlFromResource(IDR_MENU_ARROW)); | |
144 value_config.SetString( | |
145 "checkUrl", web_ui_util::GetImageDataUrlFromResource(IDR_MENU_CHECK)); | |
146 | |
147 value_config.SetString( | |
148 "scrollUpUrl", GetImageDataUrlForMenuScrollArrow(true)); | |
149 value_config.SetString( | |
150 "scrollDownUrl", GetImageDataUrlForMenuScrollArrow(false)); | |
151 | |
152 SET_INTEGER_PROPERTY(item_top_margin); | |
153 SET_INTEGER_PROPERTY(item_bottom_margin); | |
154 SET_INTEGER_PROPERTY(item_no_icon_top_margin); | |
155 SET_INTEGER_PROPERTY(item_no_icon_bottom_margin); | |
156 SET_INTEGER_PROPERTY(item_left_margin); | |
157 SET_INTEGER_PROPERTY(label_to_arrow_padding); | |
158 SET_INTEGER_PROPERTY(arrow_to_edge_padding); | |
159 SET_INTEGER_PROPERTY(icon_to_label_padding); | |
160 SET_INTEGER_PROPERTY(gutter_to_label); | |
161 SET_INTEGER_PROPERTY(check_width); | |
162 SET_INTEGER_PROPERTY(check_height); | |
163 SET_INTEGER_PROPERTY(radio_width); | |
164 SET_INTEGER_PROPERTY(radio_height); | |
165 SET_INTEGER_PROPERTY(arrow_height); | |
166 SET_INTEGER_PROPERTY(arrow_width); | |
167 SET_INTEGER_PROPERTY(gutter_width); | |
168 SET_INTEGER_PROPERTY(separator_height); | |
169 SET_INTEGER_PROPERTY(render_gutter); | |
170 SET_INTEGER_PROPERTY(show_mnemonics); | |
171 SET_INTEGER_PROPERTY(scroll_arrow_height); | |
172 SET_INTEGER_PROPERTY(label_to_accelerator_padding); | |
173 | |
174 if (delegate) | |
175 delegate->AddCustomConfigValues(&value_config); | |
176 | |
177 std::string json_config; | |
178 base::JSONWriter::Write(&value_config, false, &json_config); | |
179 | |
180 DictionaryValue strings; | |
181 | |
182 strings.SetString( | |
183 "init_script", | |
184 menu_class + ".decorate(document.getElementById('viewport'));" + | |
185 " init(" + json_config + ");"); | |
186 | |
187 if (menu_source_id == kNoExtraResource) { | |
188 strings.SetString("menu_source", ""); | |
189 } else { | |
190 base::StringPiece menu_source( | |
191 ResourceBundle::GetSharedInstance().GetRawDataResource(menu_source_id)); | |
192 strings.SetString("menu_source", menu_source.as_string()); | |
193 } | |
194 if (menu_css_id == kNoExtraResource) { | |
195 strings.SetString("menu_css", ""); | |
196 } else { | |
197 base::StringPiece menu_css( | |
198 ResourceBundle::GetSharedInstance().GetRawDataResource(menu_css_id)); | |
199 strings.SetString("menu_css", menu_css.as_string()); | |
200 } | |
201 if (delegate) | |
202 delegate->AddLocalizedStrings(&strings); | |
203 | |
204 return jstemplate_builder::GetI18nTemplateHtml(menu_template, &strings); | |
205 } | |
206 | |
207 class MenuUIHTMLSource : public ChromeURLDataManager::DataSource { | |
208 public: | |
209 MenuUIHTMLSource(const chromeos::MenuSourceDelegate* delegate, | |
210 const std::string& source_name, | |
211 const std::string& menu_class, | |
212 int menu_source_id, | |
213 int menu_css_id); | |
214 | |
215 // Called when the network layer has requested a resource underneath | |
216 // the path we registered. | |
217 virtual void StartDataRequest(const std::string& path, | |
218 bool is_off_the_record, | |
219 int request_id); | |
220 virtual std::string GetMimeType(const std::string&) const { | |
221 return "text/html"; | |
222 } | |
223 | |
224 private: | |
225 virtual ~MenuUIHTMLSource() {} | |
226 | |
227 // The menu ui the source is created for. | |
228 scoped_ptr<const chromeos::MenuSourceDelegate> delegate_; | |
229 | |
230 // The name of JS Menu class to use. | |
231 const std::string menu_class_; | |
232 | |
233 // The resource id of the JS file of the menu subclass. | |
234 int menu_source_id_; | |
235 | |
236 // The resource id of the CSS file of the menu subclass. | |
237 int menu_css_id_; | |
238 | |
239 DISALLOW_COPY_AND_ASSIGN(MenuUIHTMLSource); | |
240 }; | |
241 | |
242 // The handler for Javascript messages related to the "system" view. | |
243 class MenuHandler : public chromeos::MenuHandlerBase, | |
244 public base::SupportsWeakPtr<MenuHandler>, | |
245 public TabContentsDelegate { | |
246 public: | |
247 MenuHandler(); | |
248 virtual ~MenuHandler(); | |
249 | |
250 // WebUIMessageHandler implementation. | |
251 virtual WebUIMessageHandler* Attach(WebUI* web_ui); | |
252 virtual void RegisterMessages(); | |
253 | |
254 private: | |
255 void HandleActivate(const ListValue* values); | |
256 void HandleOpenSubmenu(const ListValue* values); | |
257 void HandleCloseSubmenu(const ListValue* values); | |
258 void HandleMoveInputToSubmenu(const ListValue* values); | |
259 void HandleMoveInputToParent(const ListValue* values); | |
260 void HandleCloseAll(const ListValue* values); | |
261 void HandleModelUpdated(const ListValue* values); | |
262 // This is a utility WebUI message to print debug message. | |
263 // Menu can't use dev tool as it lives outside of browser. | |
264 // TODO(oshima): This is inconvenient and figure out how we can use | |
265 // dev tools for menus (and other WebUI that does not belong to browser). | |
266 void HandleLog(const ListValue* values); | |
267 | |
268 // TabContentsDelegate implements: | |
269 virtual void UpdatePreferredSize(const gfx::Size& new_size); | |
270 virtual void LoadingStateChanged(TabContents* contents); | |
271 | |
272 virtual void OpenURLFromTab(TabContents* source, | |
273 const GURL& url, const GURL& referrer, | |
274 WindowOpenDisposition disposition, | |
275 PageTransition::Type transition) {} | |
276 virtual void NavigationStateChanged(const TabContents* source, | |
277 unsigned changed_flags) {} | |
278 virtual void AddNewContents(TabContents* source, | |
279 TabContents* new_contents, | |
280 WindowOpenDisposition disposition, | |
281 const gfx::Rect& initial_pos, | |
282 bool user_gesture) {} | |
283 | |
284 // TODO(oshima): Handle crash | |
285 virtual void ActivateContents(TabContents* contents) {} | |
286 virtual void DeactivateContents(TabContents* contents) {} | |
287 virtual void CloseContents(TabContents* source) {} | |
288 virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {} | |
289 virtual bool IsPopup(const TabContents* source) { return false; } | |
290 virtual void ToolbarSizeChanged(TabContents* source, bool is_animating) {} | |
291 virtual void UpdateTargetURL(TabContents* source, const GURL& url) {} | |
292 virtual bool CanDownload(int request_id) { return false; } | |
293 virtual bool infobars_enabled() { return false; } | |
294 virtual bool ShouldEnablePreferredSizeNotifications() { return true; } | |
295 virtual bool CanReloadContents(TabContents* source) const { return false; } | |
296 | |
297 // True if the page is loaded. | |
298 bool loaded_; | |
299 | |
300 DISALLOW_COPY_AND_ASSIGN(MenuHandler); | |
301 }; | |
302 | |
303 //////////////////////////////////////////////////////////////////////////////// | |
304 // | |
305 // MenuUIHTMLSource | |
306 // | |
307 //////////////////////////////////////////////////////////////////////////////// | |
308 | |
309 MenuUIHTMLSource::MenuUIHTMLSource(const chromeos::MenuSourceDelegate* delegate, | |
310 const std::string& source_name, | |
311 const std::string& menu_class, | |
312 int menu_source_id, | |
313 int menu_css_id) | |
314 : DataSource(source_name, MessageLoop::current()), | |
315 delegate_(delegate), | |
316 menu_class_(menu_class), | |
317 menu_source_id_(menu_source_id), | |
318 menu_css_id_(menu_css_id) { | |
319 } | |
320 | |
321 void MenuUIHTMLSource::StartDataRequest(const std::string& path, | |
322 bool is_off_the_record, | |
323 int request_id) { | |
324 static const base::StringPiece menu_template( | |
325 ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_MENU_HTML)); | |
326 | |
327 // The resource string should be pure code and should not contain | |
328 // i18n string. | |
329 const std::string menu_html = GetMenuUIHTMLSourceFromString( | |
330 delegate_.get(), menu_template, menu_class_, | |
331 menu_source_id_, menu_css_id_); | |
332 | |
333 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); | |
334 | |
335 // TODO(oshima): Eliminate boilerplate code. See http://crbug.com/57583 . | |
336 html_bytes->data.resize(menu_html.size()); | |
337 std::copy(menu_html.begin(), menu_html.end(), | |
338 html_bytes->data.begin()); | |
339 SendResponse(request_id, html_bytes); | |
340 } | |
341 | |
342 //////////////////////////////////////////////////////////////////////////////// | |
343 // | |
344 // MenuHandler | |
345 // | |
346 //////////////////////////////////////////////////////////////////////////////// | |
347 MenuHandler::MenuHandler() : loaded_(false) { | |
348 } | |
349 | |
350 MenuHandler::~MenuHandler() { | |
351 } | |
352 | |
353 WebUIMessageHandler* MenuHandler::Attach(WebUI* web_ui) { | |
354 WebUIMessageHandler* handler = WebUIMessageHandler::Attach(web_ui); | |
355 web_ui->tab_contents()->set_delegate(this); | |
356 return handler; | |
357 } | |
358 | |
359 void MenuHandler::RegisterMessages() { | |
360 web_ui_->RegisterMessageCallback( | |
361 "activate", | |
362 NewCallback(this, | |
363 &MenuHandler::HandleActivate)); | |
364 web_ui_->RegisterMessageCallback( | |
365 "open_submenu", | |
366 NewCallback(this, | |
367 &MenuHandler::HandleOpenSubmenu)); | |
368 web_ui_->RegisterMessageCallback( | |
369 "close_submenu", | |
370 NewCallback(this, | |
371 &MenuHandler::HandleCloseSubmenu)); | |
372 web_ui_->RegisterMessageCallback( | |
373 "move_to_submenu", | |
374 NewCallback(this, | |
375 &MenuHandler::HandleMoveInputToSubmenu)); | |
376 web_ui_->RegisterMessageCallback( | |
377 "move_to_parent", | |
378 NewCallback(this, | |
379 &MenuHandler::HandleMoveInputToParent)); | |
380 web_ui_->RegisterMessageCallback( | |
381 "close_all", | |
382 NewCallback(this, | |
383 &MenuHandler::HandleCloseAll)); | |
384 web_ui_->RegisterMessageCallback( | |
385 "model_updated", | |
386 NewCallback(this, | |
387 &MenuHandler::HandleModelUpdated)); | |
388 web_ui_->RegisterMessageCallback( | |
389 "log", | |
390 NewCallback(this, | |
391 &MenuHandler::HandleLog)); | |
392 } | |
393 | |
394 void MenuHandler::HandleActivate(const ListValue* values) { | |
395 CHECK_EQ(2U, values->GetSize()); | |
396 std::string index_str; | |
397 bool success = values->GetString(0, &index_str); | |
398 DCHECK(success); | |
399 std::string activation; | |
400 success = values->GetString(1, &activation); | |
401 DCHECK(success); | |
402 | |
403 int index; | |
404 success = base::StringToInt(index_str, &index); | |
405 DCHECK(success); | |
406 chromeos::WebUIMenuControl* control = GetMenuControl(); | |
407 if (control) { | |
408 ui::MenuModel* model = GetMenuModel(); | |
409 DCHECK(model); | |
410 DCHECK_GE(index, 0); | |
411 DCHECK(activation == "close_and_activate" || | |
412 activation == "activate_no_close") << activation; | |
413 if (model->IsEnabledAt(index)) { | |
414 control->Activate(model, | |
415 index, | |
416 activation == "close_and_activate" ? | |
417 chromeos::WebUIMenuControl::CLOSE_AND_ACTIVATE : | |
418 chromeos::WebUIMenuControl::ACTIVATE_NO_CLOSE); | |
419 } | |
420 } | |
421 } | |
422 | |
423 void MenuHandler::HandleOpenSubmenu(const ListValue* values) { | |
424 CHECK_EQ(2U, values->GetSize()); | |
425 std::string index_str; | |
426 bool success = values->GetString(0, &index_str); | |
427 DCHECK(success); | |
428 std::string y_str; | |
429 success = values->GetString(1, &y_str); | |
430 DCHECK(success); | |
431 int index; | |
432 success = base::StringToInt(index_str, &index); | |
433 DCHECK(success); | |
434 int y; | |
435 success = base::StringToInt(y_str, &y); | |
436 DCHECK(success); | |
437 chromeos::WebUIMenuControl* control = GetMenuControl(); | |
438 if (control) | |
439 control->OpenSubmenu(index, y); | |
440 } | |
441 | |
442 void MenuHandler::HandleCloseSubmenu(const ListValue* values) { | |
443 chromeos::WebUIMenuControl* control = GetMenuControl(); | |
444 if (control) | |
445 control->CloseSubmenu(); | |
446 } | |
447 | |
448 void MenuHandler::HandleMoveInputToSubmenu(const ListValue* values) { | |
449 chromeos::WebUIMenuControl* control = GetMenuControl(); | |
450 if (control) | |
451 control->MoveInputToSubmenu(); | |
452 } | |
453 | |
454 void MenuHandler::HandleMoveInputToParent(const ListValue* values) { | |
455 chromeos::WebUIMenuControl* control = GetMenuControl(); | |
456 if (control) | |
457 control->MoveInputToParent(); | |
458 } | |
459 | |
460 void MenuHandler::HandleCloseAll(const ListValue* values) { | |
461 chromeos::WebUIMenuControl* control = GetMenuControl(); | |
462 if (control) | |
463 control->CloseAll(); | |
464 } | |
465 | |
466 void MenuHandler::HandleModelUpdated(const ListValue* values) { | |
467 ui::MenuModel* model = GetMenuModel(); | |
468 if (model) | |
469 static_cast<chromeos::MenuUI*>(web_ui_)->ModelUpdated(model); | |
470 } | |
471 | |
472 void MenuHandler::HandleLog(const ListValue* values) { | |
473 CHECK_EQ(1U, values->GetSize()); | |
474 std::string msg; | |
475 bool success = values->GetString(0, &msg); | |
476 DCHECK(success); | |
477 DVLOG(1) << msg; | |
478 } | |
479 | |
480 void MenuHandler::UpdatePreferredSize(const gfx::Size& new_size) { | |
481 if (!loaded_) | |
482 return; | |
483 chromeos::WebUIMenuControl* control = GetMenuControl(); | |
484 if (control) | |
485 control->SetSize(new_size); | |
486 } | |
487 | |
488 void MenuHandler::LoadingStateChanged(TabContents* contents) { | |
489 chromeos::WebUIMenuControl* control = GetMenuControl(); | |
490 if (control && !contents->is_loading()) { | |
491 loaded_ = true; | |
492 control->OnLoad(); | |
493 HandleModelUpdated(NULL); | |
494 } | |
495 } | |
496 | |
497 } // namespace | |
498 | |
499 namespace chromeos { | |
500 | |
501 //////////////////////////////////////////////////////////////////////////////// | |
502 // | |
503 // MenuHandlerBase | |
504 // | |
505 //////////////////////////////////////////////////////////////////////////////// | |
506 | |
507 chromeos::WebUIMenuControl* MenuHandlerBase::GetMenuControl() { | |
508 WebUIMenuWidget* widget = | |
509 chromeos::WebUIMenuWidget::FindWebUIMenuWidget( | |
510 web_ui_->tab_contents()->GetNativeView()); | |
511 if (widget) | |
512 return widget->webui_menu(); // NativeMenuWebUI implements WebUIMenuControl | |
513 else | |
514 return NULL; | |
515 } | |
516 | |
517 ui::MenuModel* MenuHandlerBase::GetMenuModel() { | |
518 WebUIMenuControl* control = GetMenuControl(); | |
519 if (control) | |
520 return control->GetMenuModel(); | |
521 else | |
522 return NULL; | |
523 } | |
524 | |
525 //////////////////////////////////////////////////////////////////////////////// | |
526 // | |
527 // MenuUI | |
528 // | |
529 //////////////////////////////////////////////////////////////////////////////// | |
530 | |
531 MenuUI::MenuUI(TabContents* contents) : WebUI(contents) { | |
532 MenuHandler* handler = new MenuHandler(); | |
533 AddMessageHandler((handler)->Attach(this)); | |
534 | |
535 contents->profile()->GetChromeURLDataManager()->AddDataSource( | |
536 CreateDataSource()); | |
537 } | |
538 | |
539 MenuUI::MenuUI(TabContents* contents, ChromeURLDataManager::DataSource* source) | |
540 : WebUI(contents) { | |
541 MenuHandler* handler = new MenuHandler(); | |
542 AddMessageHandler((handler)->Attach(this)); | |
543 | |
544 contents->profile()->GetChromeURLDataManager()->AddDataSource(source); | |
545 } | |
546 | |
547 void MenuUI::ModelUpdated(const ui::MenuModel* model) { | |
548 DictionaryValue json_model; | |
549 ListValue* items = new ListValue(); | |
550 json_model.Set("items", items); | |
551 int max_icon_width = 0; | |
552 bool has_accelerator = false; | |
553 for (int index = 0; index < model->GetItemCount(); ++index) { | |
554 ui::MenuModel::ItemType type = model->GetTypeAt(index); | |
555 DictionaryValue* item; | |
556 switch (type) { | |
557 case ui::MenuModel::TYPE_SEPARATOR: | |
558 item = CreateMenuItem(model, index, "separator", | |
559 &max_icon_width, &has_accelerator); | |
560 break; | |
561 case ui::MenuModel::TYPE_RADIO: | |
562 max_icon_width = std::max(max_icon_width, 12); | |
563 item = CreateMenuItem(model, index, "radio", | |
564 &max_icon_width, &has_accelerator); | |
565 break; | |
566 case ui::MenuModel::TYPE_SUBMENU: | |
567 item = CreateMenuItem(model, index, "submenu", | |
568 &max_icon_width, &has_accelerator); | |
569 break; | |
570 case ui::MenuModel::TYPE_COMMAND: | |
571 item = CreateMenuItem(model, index, "command", | |
572 &max_icon_width, &has_accelerator); | |
573 break; | |
574 case ui::MenuModel::TYPE_CHECK: | |
575 // Add space even when unchecked. | |
576 max_icon_width = std::max(max_icon_width, 12); | |
577 item = CreateMenuItem(model, index, "check", | |
578 &max_icon_width, &has_accelerator); | |
579 break; | |
580 default: | |
581 // TODO(oshima): We don't support BUTTOM_ITEM for now. | |
582 NOTREACHED(); | |
583 continue; | |
584 } | |
585 items->Set(index, item); | |
586 } | |
587 WebUIMenuWidget* widget = | |
588 chromeos::WebUIMenuWidget::FindWebUIMenuWidget( | |
589 tab_contents()->GetNativeView()); | |
590 DCHECK(widget); | |
591 json_model.SetInteger("maxIconWidth", max_icon_width); | |
592 json_model.SetBoolean("isRoot", widget->is_root()); | |
593 json_model.SetBoolean("hasAccelerator", has_accelerator); | |
594 CallJavascriptFunction("updateModel", json_model); | |
595 } | |
596 | |
597 DictionaryValue* MenuUI::CreateMenuItem(const ui::MenuModel* model, | |
598 int index, | |
599 const char* type, | |
600 int* max_icon_width, | |
601 bool* has_accel) const { | |
602 // Note: Web UI uses '&' as mnemonic. | |
603 string16 label16 = model->GetLabelAt(index); | |
604 DictionaryValue* item = new DictionaryValue(); | |
605 | |
606 item->SetString("type", type); | |
607 item->SetString("label", label16); | |
608 item->SetBoolean("enabled", model->IsEnabledAt(index)); | |
609 item->SetBoolean("visible", model->IsVisibleAt(index)); | |
610 item->SetBoolean("checked", model->IsItemCheckedAt(index)); | |
611 item->SetInteger("command_id", model->GetCommandIdAt(index)); | |
612 item->SetString( | |
613 "font", GetFontShorthand(model->GetLabelFontAt(index))); | |
614 SkBitmap icon; | |
615 if (model->GetIconAt(index, &icon) && !icon.isNull() && !icon.empty()) { | |
616 item->SetString("icon", web_ui_util::GetImageDataUrl(icon)); | |
617 *max_icon_width = std::max(*max_icon_width, icon.width()); | |
618 } | |
619 views::Accelerator menu_accelerator; | |
620 if (model->GetAcceleratorAt(index, &menu_accelerator)) { | |
621 item->SetString("accel", menu_accelerator.GetShortcutText()); | |
622 *has_accel = true; | |
623 } | |
624 return item; | |
625 } | |
626 | |
627 // static | |
628 ChromeURLDataManager::DataSource* MenuUI::CreateMenuUIHTMLSource( | |
629 const MenuSourceDelegate* delegate, | |
630 const std::string& source_name, | |
631 const std::string& menu_class, | |
632 int menu_source_id, | |
633 int menu_css_id) { | |
634 return new MenuUIHTMLSource(delegate, | |
635 source_name, | |
636 menu_class, | |
637 menu_source_id, | |
638 menu_css_id); | |
639 } | |
640 | |
641 // static | |
642 bool MenuUI::IsEnabled() { | |
643 return CommandLine::ForCurrentProcess()->HasSwitch( | |
644 switches::kEnableWebUIMenu); | |
645 } | |
646 | |
647 ChromeURLDataManager::DataSource* MenuUI::CreateDataSource() { | |
648 return CreateMenuUIHTMLSource(NULL, | |
649 chrome::kChromeUIMenu, | |
650 "Menu" /* class name */, | |
651 kNoExtraResource, | |
652 kNoExtraResource); | |
653 } | |
654 | |
655 } // namespace chromeos | |
OLD | NEW |