view browser_side/menu.py @ 431:4fcf9bac109c

browser_side: roster management menus are now imported from the backend
author souliane <souliane@mailoo.org>
date Mon, 07 Apr 2014 23:31:21 +0200
parents f539f6f8ee9c
children 8ecc5a7062e4
line wrap: on
line source

#!/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 pyjamas.ui.SimplePanel import SimplePanel
from pyjamas.ui.MenuBar import MenuBar
from pyjamas.ui.MenuItem import MenuItem
from pyjamas.ui.ListBox import ListBox
from pyjamas.ui.Label import Label
from pyjamas.ui.TextBox import TextBox
from pyjamas.ui.HTML import HTML
from pyjamas.ui.Frame import Frame
from pyjamas import Window
from jid import JID
from html_tools import html_sanitize
from file_tools import FileUploadPanel
from xmlui import XMLUI
import panels
import dialog
from contact_group import ContactGroupEditor
import re
from sat.core.i18n import _


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(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!"}
        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 """
            print "addMenu:", 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:
                print "WARNING: skipping menu without path"
                continue
            if len(path) != len(path_i18n):
                print "ERROR: inconsistency between menu paths"
                continue
            menu_name = path[0]
            menu_name_i18n = path_i18n[0]
            item_name = path[1:]
            if not item_name:
                print "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:
                print "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 &agrave; 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

        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(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(xmlui):
            if not xmlui:
                return
            body = XMLUI(self.host, xmlui)
            _dialog = dialog.GenericDialog("Manage your XMPP account", body, options=['NO_CLOSE'])
            body.setCloseCb(_dialog.close)
            _dialog.show()
        self.host.bridge.call('getAccountDialogUI', gotUI)

    def onParameters(self):
        def gotParams(xmlui):
            if not xmlui:
                return
            body = XMLUI(self.host, xmlui)
            _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()