Mercurial > libervia-backend
diff src/core/sat_main.py @ 773:eac23b1aad90
core: dynamics menus refactoring:
- menu now use generic callback system, with extra data
- asyncMenuCall is removed in favor of launchAction
- menu_id (== callback_id) is used to identify menu instead of category/name/type tuple
- i18n is managed throught deferred translation, and returned with _i18n suffix
e.g.: menu (D_('File'), D_('Open')): (u'File', u'Open') is menu_path, (u'Fichier', u'Ouvrir') is french menu_path_i18n.
- type actually can have the following values:
- NORMAL: classical menu
- JID_CONTEXT: contextual menu, used with any jid
- ROSTER_JID_CONTEXT: like JID_CONTEXT, but restricted to jids in roster.
- ROSTER_GROUP_CONTEXT: contextual menu, use with groups
- security_limit is used, in the same way as for parameters
- when using importMenu, callback can be an actual callback, or one already registered with registerCallback
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 29 Dec 2013 17:10:14 +0100 |
parents | bfabeedbf32e |
children | 5642939d254e |
line wrap: on
line diff
--- a/src/core/sat_main.py Sun Dec 29 17:10:10 2013 +0100 +++ b/src/core/sat_main.py Sun Dec 29 17:10:14 2013 +0100 @@ -17,7 +17,7 @@ # 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/>. -from sat.core.i18n import _ +from sat.core.i18n import _, languageSwitch from twisted.application import service from twisted.internet import defer @@ -39,7 +39,7 @@ from sat.core.default_config import CONST from sat.core import xmpp from sat.core import exceptions -from sat.memory.memory import Memory +from sat.memory.memory import Memory, NO_SECURITY_LIMIT from sat.tools.xml_tools import tupleList2dataForm from sat.tools.misc import TriggerManager from glob import glob @@ -106,10 +106,10 @@ def __init__(self): self._cb_map = {} # map from callback_id to callbacks + self._menus = {} # dynamic menus. key: callback_id, value: menu data (dictionnary) self.__private_data = {} # used for internal callbacks (key = id) FIXME: to be removed self.profiles = {} self.plugins = {} - self.menus = {} # dynamic menus. key: (type, category, name), value: menu data (dictionnary) self.memory = Memory(self) @@ -162,7 +162,6 @@ self.bridge.register("getProgress", self.getProgress) self.bridge.register("getMenus", self.getMenus) self.bridge.register("getMenuHelp", self.getMenuHelp) - self.bridge.register("asyncCallMenu", self.callMenu) self.memory.initialized.addCallback(self._postMemoryInit) @@ -891,57 +890,85 @@ #Menus management - def importMenu(self, category, name, callback, callback_args=None, callback_kwargs=None, help_string="", type_="NORMAL"): + def importMenu(self, path, callback, security_limit=NO_SECURITY_LIMIT, help_string="", type_="NORMAL"): """register a new menu for frontends - @param category: category of the menu - @param name: menu item entry - @param callback: method to be called when menuitem is selected - @param callback_args: optional arguments to forward to callback - @param callback_kwargs: optional keywords arguments to forward to callback + @param path: path to go to the menu (category/subcategory/.../item), must be an iterable (e.g.: ("File", "Open")) + /!\ use D_() instead of _() for translations (e.g. (D_("File"), D_("Open"))) + @param callback: method to be called when menuitem is selected, callable or a callback id (string) as returned by [registerCallback] + @param security_limit: %(doc_security_limit)s + /!\ security_limit MUST be added to data in launchCallback if used + @param help_string: string used to indicate what the menu do (can be show as a tooltip). + /!\ use D_() instead of _() for translations + @param type: one of: + - NORMAL: classical menu, can be shown in a menubar on top (e.g. something like File/Open) + - JID_CONTEXT: contextual menu, used with any jid (e.g.: ad hoc commands, jid is already filled) + - ROSTER_JID_CONTEXT: like JID_CONTEXT, but restricted to jids in roster. + - ROSTER_GROUP_CONTEXT: contextual menu, used with group (e.g.: publish microblog, group is already filled) + @return: menu_id (same as callback_id) """ - # TODO: manage translations - if (type_, category, name) in self.menus: - raise exceptions.ConflictError("Menu already exists") - menu_data = {'callback': callback, 'help_string': help_string} - if callback_args is not None: - assert(isinstance(callback_args, list)) - menu_data['callback_args'] = callback_args - if callback_kwargs is not None: - assert(isinstance(callback_kwargs, dict)) - menu_data['callback_kwargs'] = callback_kwargs - self.menus[(type_, category, name)] = menu_data + + if callable(callback): + callback_id = self.registerCallback(callback, with_data=True) + elif isinstance(callback, basestring): + # The callback is already registered + callback_id = callback + try: + callback, args, kwargs = self._cb_map[callback_id] + except KeyError: + raise exceptions.DataError("Unknown callback id") + kwargs["with_data"] = True # we have to be sure that we use extra data + else: + raise exceptions.DataError("Unknown callback type") + + for menu_data in self._menus.itervalues(): + if menu_data['path'] == path and menu_data['type'] == type_: + raise exceptions.ConflictError(_("A menu with the same path and type already exists")) + + menu_data = {'path': path, + 'security_limit': security_limit, + 'help_string': help_string, + 'type': type_ + } + + self._menus[callback_id] = menu_data + + return callback_id - def getMenus(self): - """Return all menus registered""" - # TODO: manage translations - return self.menus.keys() + def getMenus(self, language='', security_limit = NO_SECURITY_LIMIT): + """Return all menus registered + @param language: language used for translation, or empty string for default + @param security_limit: %(doc_security_limit)s + @return: array of tuple with: + - menu id (same as callback_id) + - menu type + - raw menu path (array of strings) + - translated menu path - def getMenuHelp(self, category, name, type_="NORMAL"): - """return the help string of the menu""" - # TODO: manage translations + """ + ret = [] + for menu_id, menu_data in self._menus.iteritems(): + type_ = menu_data['type'] + path = menu_data['path'] + languageSwitch(language) + path_i18n = [_(elt) for elt in path] + languageSwitch() + ret.append((menu_id, type_, path, path_i18n)) + + return ret + + def getMenuHelp(self, menu_id, language=''): + """ + return the help string of the menu + @param menu_id: id of the menu (same as callback_id) + @param language: language used for translation, or empty string for default + @param return: translated help + + """ try: - return self.menus[(type_, category, name)]['help_string'] + menu_data = self._menus[menu_id] except KeyError: raise exceptions.DataError("Trying to access an unknown menu") - - def callMenu(self, category, name, type_="NORMAL", profile_key='@NONE@'): - """ Call a dynamic menu - @param category: category of the menu to call - @param name: name of the menu to call - @param type_: type of the menu to call - @param profile_key: %(doc_profile_key)s - @return: XMLUI or empty string if it's a one shot menu - """ - # TODO: menus should use launchCallback - profile = self.memory.getProfileName(profile_key) - if not profile: - raise exceptions.ProfileUnknownError - menu_data = self.menus[(type_, category, name)] - callback = menu_data['callback'] - args = menu_data.get('callback_args', ()) - kwargs = menu_data.get('callback_kwargs', {}).copy() - kwargs["profile"] = profile - try: - return defer.maybeDeferred(callback, *args, **kwargs) - except KeyError: - raise exceptions.DataError("Trying to access an unknown menu (%(type)s/%(category)s/%(name)s)" % {'type': type_, 'category': category, 'name': name}) + languageSwitch(language) + help_string = _(menu_data['help_string']) + languageSwitch() + return help_string