15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/menu_model_adapter.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/models/menu_model.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/menu/submenu_view.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/views_delegate.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views { 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MenuModelAdapter::MenuModelAdapter(ui::MenuModel* menu_model) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : menu_model_(menu_model), 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) triggerable_event_flags_(ui::EF_LEFT_MOUSE_BUTTON | 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::EF_RIGHT_MOUSE_BUTTON) { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(menu_model); 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MenuModelAdapter::~MenuModelAdapter() { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MenuModelAdapter::BuildMenu(MenuItemView* menu) { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(menu); 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clear the menu. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (menu->HasSubmenu()) { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int subitem_count = menu->GetSubmenu()->child_count(); 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < subitem_count; ++i) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu->RemoveMenuItemAt(0); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Leave entries in the map if the menu is being shown. This 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allows the map to find the menu model of submenus being closed 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so ui::MenuModel::MenuClosed() can be called. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!menu->GetMenuController()) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_map_.clear(); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_map_[menu] = menu_model_; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Repopulate the menu. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BuildMenuImpl(menu, menu_model_); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu->ChildrenChanged(); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MenuItemView* MenuModelAdapter::CreateMenu() { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MenuItemView* item = new MenuItemView(this); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BuildMenu(item); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return item; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MenuItemView* MenuModelAdapter::AppendMenuItem(MenuItemView* menu, 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::MenuModel* model, 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int index) { 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return menu->AppendMenuItemFromModel(model, index, 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) model->GetCommandIdAt(index)); 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuModelAdapter, MenuDelegate implementation: 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MenuModelAdapter::ExecuteCommand(int id) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::MenuModel* model = menu_model_; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = 0; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model->ActivatedAt(index); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MenuModelAdapter::ExecuteCommand(int id, int mouse_event_flags) { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::MenuModel* model = menu_model_; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = 0; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model->ActivatedAt(index, mouse_event_flags); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MenuModelAdapter::IsTriggerableEvent(MenuItemView* source, 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ui::Event& e) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return e.type() == ui::ET_GESTURE_TAP || 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) e.type() == ui::ET_GESTURE_TAP_DOWN || 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (e.IsMouseEvent() && (triggerable_event_flags_ & e.flags()) != 0); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MenuModelAdapter::GetAccelerator(int id, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::Accelerator* accelerator) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::MenuModel* model = menu_model_; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = 0; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return model->GetAcceleratorAt(index, accelerator); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string16 MenuModelAdapter::GetLabel(int id) const { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::MenuModel* model = menu_model_; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = 0; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return model->GetLabelAt(index); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return string16(); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const gfx::Font* MenuModelAdapter::GetLabelFont(int id) const { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::MenuModel* model = menu_model_; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = 0; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Font* font = model->GetLabelFontAt(index); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (font) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return font; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This line may be reached for the empty menu item. 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MenuDelegate::GetLabelFont(id); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MenuModelAdapter::IsCommandEnabled(int id) const { 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::MenuModel* model = menu_model_; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = 0; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return model->IsEnabledAt(index); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MenuModelAdapter::IsItemChecked(int id) const { 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::MenuModel* model = menu_model_; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = 0; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return model->IsItemCheckedAt(index); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MenuModelAdapter::SelectionChanged(MenuItemView* menu) { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore selection of the root menu. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (menu == menu->GetRootMenuItem()) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int id = menu->GetCommand(); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::MenuModel* model = menu_model_; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index = 0; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model->HighlightChangedTo(index); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MenuModelAdapter::WillShowMenu(MenuItemView* menu) { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Look up the menu model for this menu. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator = 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_map_.find(menu); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (map_iterator != menu_map_.end()) { 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) map_iterator->second->MenuWillShow(); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MenuModelAdapter::WillHideMenu(MenuItemView* menu) { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Look up the menu model for this menu. 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator = 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_map_.find(menu); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (map_iterator != menu_map_.end()) { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) map_iterator->second->MenuClosed(); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuModelAdapter, private: 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MenuModelAdapter::BuildMenuImpl(MenuItemView* menu, ui::MenuModel* model) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(menu); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(model); 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool has_icons = model->HasIcons(); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int item_count = model->GetItemCount(); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < item_count; ++i) { 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MenuItemView* item = AppendMenuItem(menu, model, i); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (item) 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) item->SetVisible(model->IsVisibleAt(i)); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (model->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(item); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(MenuItemView::SUBMENU, item->GetType()); 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::MenuModel* submodel = model->GetSubmenuModelAt(i); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(submodel); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BuildMenuImpl(item, submodel); 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) has_icons = has_icons || item->has_icons(); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) menu_map_[item] = submodel; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) menu->set_has_icons(has_icons); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace views 214