Mercurial > libervia-web
diff src/browser/sat_browser/menu.py @ 467:97c72fe4a5f2
browser_side: import fixes:
- moved browser modules in a sat_browser packages, to avoid import conflicts with std lib (e.g. logging), and let pyjsbuild work normaly
- refactored bad import practices: classes are most of time not imported directly, module is imported instead.
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 09 Jun 2014 22:15:26 +0200 |
parents | src/browser/menu.py@bea9788f3170 |
children | a7f5448a1bc3 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/browser/sat_browser/menu.py Mon Jun 09 22:15:26 2014 +0200 @@ -0,0 +1,271 @@ +#!/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/>. + +import pyjd # this is dummy in pyjs +from sat.core.log import getLogger +log = getLogger(__name__) + +from sat.core.i18n import _ + +from pyjamas.ui.SimplePanel import SimplePanel +from pyjamas.ui.MenuBar import MenuBar +from pyjamas.ui.MenuItem import MenuItem +from pyjamas.ui.HTML import HTML +from pyjamas.ui.Frame import Frame +from pyjamas import Window + +import jid + +import file_tools +import xmlui +import panels +import dialog +import contact_group + + +class MenuCmd: + + def __init__(self, object_, handler): + self._object = object_ + self._handler = handler + + def execute(self): + handler = getattr(self._object, self._handler) + handler() + + +class PluginMenuCmd: + + def __init__(self, host, action_id): + self.host = host + self.action_id = action_id + + def execute(self): + self.host.launchAction(self.action_id, None) + + +class LiberviaMenuBar(MenuBar): + + def __init__(self): + MenuBar.__init__(self, vertical=False) + self.setStyleName('gwt-MenuBar-horizontal') # XXX: workaround for the Pyjamas' class name fix (it's now "gwt-MenuBar gwt-MenuBar-horizontal") + # TODO: properly adapt CSS to the new class name + + def doItemAction(self, item, fireCommand): + MenuBar.doItemAction(self, item, fireCommand) + if item == self.items[-1] and self.popup: + self.popup.setPopupPosition(Window.getClientWidth() - + self.popup.getOffsetWidth() - 22, + self.getAbsoluteTop() + + self.getOffsetHeight() - 1) + self.popup.addStyleName('menuLastPopup') + + +class AvatarUpload(file_tools.FileUploadPanel): + def __init__(self): + texts = {'ok_button': 'Upload avatar', + 'body': 'Please select an image to show as your avatar...<br>Your picture must be a square and will be resized to 64x64 pixels if necessary.', + 'errback': "Can't open image... did you actually submit an image?", + 'body_errback': 'Please select another image file.', + 'callback': "Your new profile picture has been set!"} + file_tools.FileUploadPanel.__init__(self, 'upload_avatar', 'avatar_path', 2, texts) + + +class Menu(SimplePanel): + + def __init__(self, host): + self.host = host + SimplePanel.__init__(self) + self.setStyleName('menuContainer') + + def createMenus(self, add_menus): + _item_tpl = "<img src='media/icons/menu/%s_menu_red.png' />%s" + menus_dict = {} + menus_order = [] + + def addMenu(menu_name, menu_name_i18n, item_name_i18n, icon, menu_cmd): + """ add a menu to menu_dict """ + log.info("addMenu: %s %s %s %s %s" % (menu_name, menu_name_i18n, item_name_i18n, icon, menu_cmd)) + try: + menu_bar = menus_dict[menu_name] + except KeyError: + menu_bar = menus_dict[menu_name] = MenuBar(vertical=True) + menus_order.append((menu_name, menu_name_i18n, icon)) + if item_name_i18n and menu_cmd: + menu_bar.addItem(item_name_i18n, menu_cmd) + + addMenu("General", _("General"), _("Web widget"), 'home', MenuCmd(self, "onWebWidget")) + addMenu("General", _("General"), _("Disconnect"), 'home', MenuCmd(self, "onDisconnect")) + addMenu("Contacts", _("Contacts"), None, 'social', None) + addMenu("Groups", _("Groups"), _("Discussion"), 'social', MenuCmd(self, "onJoinRoom")) + addMenu("Groups", _("Groups"), _("Collective radio"), 'social', MenuCmd(self, "onCollectiveRadio")) + addMenu("Games", _("Games"), _("Tarot"), 'games', MenuCmd(self, "onTarotGame")) + addMenu("Games", _("Games"), _("Xiangqi"), 'games', MenuCmd(self, "onXiangqiGame")) + + # additional menus + for action_id, type_, path, path_i18n in add_menus: + if not path: + log.warning("skipping menu without path") + continue + if len(path) != len(path_i18n): + log.error("inconsistency between menu paths") + continue + menu_name = path[0] + menu_name_i18n = path_i18n[0] + item_name = path[1:] + if not item_name: + log.warning("skipping menu with a path of lenght 1 [%s]" % path[0]) + continue + item_name_i18n = ' | '.join(path_i18n[1:]) + addMenu(menu_name, menu_name_i18n, item_name_i18n, 'plugins', PluginMenuCmd(self.host, action_id)) + + # menu items that should be displayed after the automatically added ones + addMenu("Contacts", _("Contacts"), _("Manage groups"), 'social', MenuCmd(self, "onManageContactGroups")) + + menus_order.append(None) # we add separator + + addMenu("Help", _("Help"), _("Social contract"), 'help', MenuCmd(self, "onSocialContract")) + addMenu("Help", _("Help"), _("About"), 'help', MenuCmd(self, "onAbout")) + addMenu("Settings", _("Settings"), _("Account"), 'settings', MenuCmd(self, "onAccount")) + addMenu("Settings", _("Settings"), _("Parameters"), 'settings', MenuCmd(self, "onParameters")) + + # XXX: temporary, will change when a full profile will be managed in SàT + addMenu("Settings", _("Settings"), _("Upload avatar"), 'settings', MenuCmd(self, "onAvatarUpload")) + + menubar = LiberviaMenuBar() + + for menu_data in menus_order: + if menu_data is None: + _separator = MenuItem('', None) + _separator.setStyleName('menuSeparator') + menubar.addItem(_separator, None) + else: + menu_name, menu_name_i18n, icon = menu_data + menubar.addItem(MenuItem(_item_tpl % (icon, menu_name_i18n), True, menus_dict[menu_name])) + + self.add(menubar) + + #General menu + def onWebWidget(self): + web_panel = panels.WebPanel(self.host, "http://www.goffi.org") + self.host.addWidget(web_panel) + self.host.setSelected(web_panel) + + def onDisconnect(self): + def confirm_cb(answer): + if answer: + log.info("disconnection") + self.host.bridge.call('disconnect', None) + _dialog = dialog.ConfirmDialog(confirm_cb, text="Do you really want to disconnect ?") + _dialog.show() + + def onSocialContract(self): + _frame = Frame('contrat_social.html') + _frame.setStyleName('infoFrame') + _dialog = dialog.GenericDialog("Contrat Social", _frame) + _dialog.setSize('80%', '80%') + _dialog.show() + + def onAbout(self): + _about = HTML("""<b>Libervia</b>, a Salut à Toi project<br /> +<br /> +You can contact the author at <a href="mailto:goffi@goffi.org">goffi@goffi.org</a><br /> +Blog available (mainly in french) at <a href="http://www.goffi.org" target="_blank">http://www.goffi.org</a><br /> +Project page: <a href="http://sat.goffi.org"target="_blank">http://sat.goffi.org</a><br /> +<br /> +Any help welcome :) +<p style='font-size:small;text-align:center'>This project is dedicated to Roger Poisson</p> +""") + _dialog = dialog.GenericDialog("About", _about) + _dialog.show() + + #Contact menu + def onManageContactGroups(self): + """Open the contact groups manager.""" + + def onCloseCallback(): + pass + + contact_group.ContactGroupEditor(self.host, None, onCloseCallback) + + #Group menu + def onJoinRoom(self): + + def invite(room_jid, contacts): + for contact in contacts: + self.host.bridge.call('inviteMUC', None, contact, room_jid) + + def join(room_jid, contacts): + if self.host.whoami: + nick = self.host.whoami.node + if room_jid not in [room.bare for room in self.host.room_list]: + self.host.bridge.call('joinMUC', lambda room_jid: invite(room_jid, contacts), room_jid, nick) + else: + self.host.getOrCreateLiberviaWidget(panels.ChatPanel, (room_jid, "group"), True, jid.JID(room_jid).bare) + invite(room_jid, contacts) + + dialog.RoomAndContactsChooser(self.host, join, ok_button="Join", visible=(True, False)) + + def onCollectiveRadio(self): + def callback(room_jid, contacts): + self.host.bridge.call('launchRadioCollective', None, contacts, room_jid) + dialog.RoomAndContactsChooser(self.host, callback, ok_button="Choose", title="Collective Radio", visible=(False, True)) + + #Game menu + def onTarotGame(self): + def onPlayersSelected(room_jid, other_players): + self.host.bridge.call('launchTarotGame', None, other_players, room_jid) + dialog.RoomAndContactsChooser(self.host, onPlayersSelected, 3, title="Tarot", title_invite="Please select 3 other players", visible=(False, True)) + + def onXiangqiGame(self): + Window.alert("A Xiangqi game is planed, but not available yet") + + #Settings menu + + def onAccount(self): + def gotUI(xml_ui): + if not xml_ui: + return + body = xmlui.XMLUI(self.host, xml_ui) + _dialog = dialog.GenericDialog("Manage your account", body, options=['NO_CLOSE']) + body.setCloseCb(_dialog.close) + _dialog.show() + self.host.bridge.call('getAccountDialogUI', gotUI) + + def onParameters(self): + def gotParams(xml_ui): + if not xml_ui: + return + body = xmlui.XMLUI(self.host, xml_ui) + _dialog = dialog.GenericDialog("Parameters", body, options=['NO_CLOSE']) + body.setCloseCb(_dialog.close) + _dialog.setSize('80%', '80%') + _dialog.show() + self.host.bridge.call('getParamsUI', gotParams) + + def removeItemParams(self): + """Remove the Parameters item from the Settings menu bar.""" + self.menu_settings.removeItem(self.item_params) + + def onAvatarUpload(self): + body = AvatarUpload() + _dialog = dialog.GenericDialog("Avatar upload", body, options=['NO_CLOSE']) + body.setCloseCb(_dialog.close) + _dialog.setWidth('40%') + _dialog.show()