Mercurial > libervia-web
diff src/browser/sat_browser/base_menu.py @ 494:5d8632a7bfde
browser_side: refactorisation of menus and LiberviaWidget's header
author | souliane <souliane@mailoo.org> |
---|---|
date | Tue, 15 Jul 2014 18:43:55 +0200 |
parents | |
children | 60be99de3808 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/browser/sat_browser/base_menu.py Tue Jul 15 18:43:55 2014 +0200 @@ -0,0 +1,166 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Libervia: a Salut à Toi frontend +# Copyright (C) 2011, 2012, 2013, 2014 Jérôme Poisson <goffi@goffi.org> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +"""Base classes for building a menu. + +These classes have been moved here from menu.py because they are also used +by base_widget.py, and the import sequence caused a JS runtime error.""" + + +import pyjd # this is dummy in pyjs +from sat.core.log import getLogger +log = getLogger(__name__) + +from pyjamas.ui.MenuBar import MenuBar +from pyjamas.ui.MenuItem import MenuItem + + +class MenuCmd: + """Return an object with an "execute" method that can be set to a menu item callback""" + + def __init__(self, object_, handler): + self._object = object_ + self._handler = handler + + def execute(self): + handler = getattr(self._object, self._handler) + handler() + + +class PluginMenuCmd: + """Like MenuCmd, but instead of executing a method, it will command the bridge to launch an action""" + + def __init__(self, host, action_id, menu_data=None): + self.host = host + self.action_id = action_id + self.menu_data = menu_data + + def execute(self): + self.host.launchAction(self.action_id, self.menu_data) + + +class CategoryMenuBar(MenuBar): + """A menu bar for a category (sub menu)""" + def __init__(self): + MenuBar.__init__(self, vertical=True) + + +class CategoryItem(MenuItem): + """A category item with a non-internationalized name""" + def __init__(self, name, *args, **kwargs): + MenuItem.__init__(self, *args, **kwargs) + self.name = name + + +class GenericMenuBar(MenuBar): + + def __init__(self, host, vertical=False, **kwargs): + MenuBar.__init__(self, vertical, **kwargs) + self.host = host + self.moved_popup_style = None + + @classmethod + def getCategoryHTML(cls, type_, menu_name_i18n): + """Build from the given parameters the html to be displayed for a category item. + + Inheriting classes may overwrite this method. + @param type_ (str): category type + @param menu_name_i18n (str): internationalized category name + @return: str + """ + return menu_name_i18n + + def doItemAction(self, item, fireCommand): + """Overwrites the default behavior for the popup menu to fit in the screen""" + MenuBar.doItemAction(self, item, fireCommand) + if not self.vertical and self.popup: + # we not only move the last popup, but any which would go over the menu right extremity + most_left = self.getAbsoluteLeft() + self.getOffsetWidth() - self.popup.getOffsetWidth() + if item.getAbsoluteLeft() > most_left: + self.popup.setPopupPosition(most_left, + self.getAbsoluteTop() + + self.getOffsetHeight() - 1) + # eventually smooth the popup edges to fit the menu own style + if self.moved_popup_style: + self.popup.addStyleName(self.moved_popup_style) + + def getCategories(self): + """Return the categories items. + + @return: list[CategoryItem] + """ + return [item for item in self.items if isinstance(item, CategoryItem)] + + def getSubMenu(self, category): + """Return the popup menu for the given category + + @param category (str): category name + @return: CategoryMenuBar instance or None + """ + try: + return [item for item in self.items if isinstance(item, CategoryItem) and item.name == category][0].getSubMenu() + except IndexError: + return None + + def addSeparator(self): + """Add a separator between the categories""" + self.addItem(CategoryItem(None, text='', asHTML=None, StyleName='menuSeparator')) + + def addCategory(self, menu_name, menu_name_i18n, type_, sub_menu): + """Add a category + + @param menu_name (str): category name + @param menu_name_i18n (str): internationalized category name + @param type_ (str): category type + @param sub_menu (CategoryMenuBar): category sub-menu + """ + html = self.getCategoryHTML(type_, menu_name_i18n) + self.addItem(CategoryItem(menu_name, text=html, asHTML=True, subMenu=sub_menu)) + + def addMenu(self, menu_name, menu_name_i18n, item_name_i18n, type_, menu_cmd): + """Add a new menu item + @param menu_name (str): category name + @param menu_name_i18n (str): internationalized menu name + @param item_name_i18n (str): internationalized item name + @param type_ (str): category type in ('games', 'help', 'home', 'photos', 'plugins', 'settings', 'social') + @param menu_cmd (MenuCmd or PluginMenuCmd): instance to execute as the item callback + """ + log.info("addMenu: %s %s %s %s %s" % (menu_name, menu_name_i18n, item_name_i18n, type_, menu_cmd)) + sub_menu = self.getSubMenu(menu_name) + if not sub_menu: + sub_menu = CategoryMenuBar() + self.addCategory(menu_name, menu_name_i18n, type_, sub_menu) + if item_name_i18n and menu_cmd: + sub_menu.addItem(item_name_i18n, menu_cmd) + + def addCachedMenus(self, type_, menu_data=None): + """Add cached menus to instance + @param type_: menu type like is sat.core.sat_main.importMenu + @param menu_data: data to send with these menus + """ + menus = self.host.menus.get(type_, []) + for action_id, path, path_i18n in menus: + if len(path) != 2: + raise NotImplementedError("Menu with a path != 2 are not implemented yet") + if len(path) != len(path_i18n): + log.error("inconsistency between menu paths") + continue + callback = PluginMenuCmd(self.host, action_id, menu_data) + self.addMenu(path[0], path_i18n[0], path_i18n[1], 'plugins', callback)