comparison src/browser/menu.py @ 449:981ed669d3b3

/!\ reorganize all the file hierarchy, move the code and launching script to src: - browser_side --> src/browser - public --> src/browser_side/public - libervia.py --> src/browser/libervia_main.py - libervia_server --> src/server - libervia_server/libervia.sh --> src/libervia.sh - twisted --> src/twisted - new module src/common - split constants.py in 3 files: - src/common/constants.py - src/browser/constants.py - src/server/constants.py - output --> html (generated by pyjsbuild during the installation) - new option/parameter "data_dir" (-d) to indicates the directory containing html and server_css - setup.py installs libervia to the following paths: - src/common --> <LIB>/libervia/common - src/server --> <LIB>/libervia/server - src/twisted --> <LIB>/twisted - html --> <SHARE>/libervia/html - server_side --> <SHARE>libervia/server_side - LIBERVIA_INSTALL environment variable takes 2 new options with prompt confirmation: - clean: remove previous installation directories - purge: remove building and previous installation directories You may need to update your sat.conf and/or launching script to update the following options/parameters: - ssl_certificate - data_dir
author souliane <souliane@mailoo.org>
date Tue, 20 May 2014 06:41:16 +0200
parents browser_side/menu.py@d52f529a6d42
children bea9788f3170
comparison
equal deleted inserted replaced
448:14c35f7f1ef5 449:981ed669d3b3
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 # Libervia: a Salut à Toi frontend
5 # Copyright (C) 2011, 2012, 2013, 2014 Jérôme Poisson <goffi@goffi.org>
6
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
16
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 import pyjd # this is dummy in pyjs
21 from sat.core.log import getLogger
22 log = getLogger(__name__)
23
24 from sat.core.i18n import _
25
26 from pyjamas.ui.SimplePanel import SimplePanel
27 from pyjamas.ui.MenuBar import MenuBar
28 from pyjamas.ui.MenuItem import MenuItem
29 from pyjamas.ui.HTML import HTML
30 from pyjamas.ui.Frame import Frame
31 from pyjamas import Window
32
33 from jid import JID
34
35 from file_tools import FileUploadPanel
36 from xmlui import XMLUI
37 import panels
38 import dialog
39 from contact_group import ContactGroupEditor
40
41
42 class MenuCmd:
43
44 def __init__(self, object_, handler):
45 self._object = object_
46 self._handler = handler
47
48 def execute(self):
49 handler = getattr(self._object, self._handler)
50 handler()
51
52
53 class PluginMenuCmd:
54
55 def __init__(self, host, action_id):
56 self.host = host
57 self.action_id = action_id
58
59 def execute(self):
60 self.host.launchAction(self.action_id, None)
61
62
63 class LiberviaMenuBar(MenuBar):
64
65 def __init__(self):
66 MenuBar.__init__(self, vertical=False)
67 self.setStyleName('gwt-MenuBar-horizontal') # XXX: workaround for the Pyjamas' class name fix (it's now "gwt-MenuBar gwt-MenuBar-horizontal")
68 # TODO: properly adapt CSS to the new class name
69
70 def doItemAction(self, item, fireCommand):
71 MenuBar.doItemAction(self, item, fireCommand)
72 if item == self.items[-1] and self.popup:
73 self.popup.setPopupPosition(Window.getClientWidth() -
74 self.popup.getOffsetWidth() - 22,
75 self.getAbsoluteTop() +
76 self.getOffsetHeight() - 1)
77 self.popup.addStyleName('menuLastPopup')
78
79
80 class AvatarUpload(FileUploadPanel):
81 def __init__(self):
82 texts = {'ok_button': 'Upload avatar',
83 '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.',
84 'errback': "Can't open image... did you actually submit an image?",
85 'body_errback': 'Please select another image file.',
86 'callback': "Your new profile picture has been set!"}
87 FileUploadPanel.__init__(self, 'upload_avatar', 'avatar_path', 2, texts)
88
89
90 class Menu(SimplePanel):
91
92 def __init__(self, host):
93 self.host = host
94 SimplePanel.__init__(self)
95 self.setStyleName('menuContainer')
96
97 def createMenus(self, add_menus):
98 _item_tpl = "<img src='media/icons/menu/%s_menu_red.png' />%s"
99 menus_dict = {}
100 menus_order = []
101
102 def addMenu(menu_name, menu_name_i18n, item_name_i18n, icon, menu_cmd):
103 """ add a menu to menu_dict """
104 log.info("addMenu: %s %s %s %s %s" % (menu_name, menu_name_i18n, item_name_i18n, icon, menu_cmd))
105 try:
106 menu_bar = menus_dict[menu_name]
107 except KeyError:
108 menu_bar = menus_dict[menu_name] = MenuBar(vertical=True)
109 menus_order.append((menu_name, menu_name_i18n, icon))
110 if item_name_i18n and menu_cmd:
111 menu_bar.addItem(item_name_i18n, menu_cmd)
112
113 addMenu("General", _("General"), _("Web widget"), 'home', MenuCmd(self, "onWebWidget"))
114 addMenu("General", _("General"), _("Disconnect"), 'home', MenuCmd(self, "onDisconnect"))
115 addMenu("Contacts", _("Contacts"), None, 'social', None)
116 addMenu("Groups", _("Groups"), _("Discussion"), 'social', MenuCmd(self, "onJoinRoom"))
117 addMenu("Groups", _("Groups"), _("Collective radio"), 'social', MenuCmd(self, "onCollectiveRadio"))
118 addMenu("Games", _("Games"), _("Tarot"), 'games', MenuCmd(self, "onTarotGame"))
119 addMenu("Games", _("Games"), _("Xiangqi"), 'games', MenuCmd(self, "onXiangqiGame"))
120
121 # additional menus
122 for action_id, type_, path, path_i18n in add_menus:
123 if not path:
124 log.warning("skipping menu without path")
125 continue
126 if len(path) != len(path_i18n):
127 log.error("inconsistency between menu paths")
128 continue
129 menu_name = path[0]
130 menu_name_i18n = path_i18n[0]
131 item_name = path[1:]
132 if not item_name:
133 log.warning("skipping menu with a path of lenght 1 [%s]" % path[0])
134 continue
135 item_name_i18n = ' | '.join(path_i18n[1:])
136 addMenu(menu_name, menu_name_i18n, item_name_i18n, 'plugins', PluginMenuCmd(self.host, action_id))
137
138 # menu items that should be displayed after the automatically added ones
139 addMenu("Contacts", _("Contacts"), _("Manage groups"), 'social', MenuCmd(self, "onManageContactGroups"))
140
141 menus_order.append(None) # we add separator
142
143 addMenu("Help", _("Help"), _("Social contract"), 'help', MenuCmd(self, "onSocialContract"))
144 addMenu("Help", _("Help"), _("About"), 'help', MenuCmd(self, "onAbout"))
145 addMenu("Settings", _("Settings"), _("Account"), 'settings', MenuCmd(self, "onAccount"))
146 addMenu("Settings", _("Settings"), _("Parameters"), 'settings', MenuCmd(self, "onParameters"))
147
148 # XXX: temporary, will change when a full profile will be managed in SàT
149 addMenu("Settings", _("Settings"), _("Upload avatar"), 'settings', MenuCmd(self, "onAvatarUpload"))
150
151 menubar = LiberviaMenuBar()
152
153 for menu_data in menus_order:
154 if menu_data is None:
155 _separator = MenuItem('', None)
156 _separator.setStyleName('menuSeparator')
157 menubar.addItem(_separator, None)
158 else:
159 menu_name, menu_name_i18n, icon = menu_data
160 menubar.addItem(MenuItem(_item_tpl % (icon, menu_name_i18n), True, menus_dict[menu_name]))
161
162 self.add(menubar)
163
164 #General menu
165 def onWebWidget(self):
166 web_panel = panels.WebPanel(self.host, "http://www.goffi.org")
167 self.host.addWidget(web_panel)
168 self.host.setSelected(web_panel)
169
170 def onDisconnect(self):
171 def confirm_cb(answer):
172 if answer:
173 log.info("disconnection")
174 self.host.bridge.call('disconnect', None)
175 _dialog = dialog.ConfirmDialog(confirm_cb, text="Do you really want to disconnect ?")
176 _dialog.show()
177
178 def onSocialContract(self):
179 _frame = Frame('contrat_social.html')
180 _frame.setStyleName('infoFrame')
181 _dialog = dialog.GenericDialog("Contrat Social", _frame)
182 _dialog.setSize('80%', '80%')
183 _dialog.show()
184
185 def onAbout(self):
186 _about = HTML("""<b>Libervia</b>, a Salut &agrave; Toi project<br />
187 <br />
188 You can contact the author at <a href="mailto:goffi@goffi.org">goffi@goffi.org</a><br />
189 Blog available (mainly in french) at <a href="http://www.goffi.org" target="_blank">http://www.goffi.org</a><br />
190 Project page: <a href="http://sat.goffi.org"target="_blank">http://sat.goffi.org</a><br />
191 <br />
192 Any help welcome :)
193 <p style='font-size:small;text-align:center'>This project is dedicated to Roger Poisson</p>
194 """)
195 _dialog = dialog.GenericDialog("About", _about)
196 _dialog.show()
197
198 #Contact menu
199 def onManageContactGroups(self):
200 """Open the contact groups manager."""
201
202 def onCloseCallback():
203 pass
204
205 ContactGroupEditor(self.host, None, onCloseCallback)
206
207 #Group menu
208 def onJoinRoom(self):
209
210 def invite(room_jid, contacts):
211 for contact in contacts:
212 self.host.bridge.call('inviteMUC', None, contact, room_jid)
213
214 def join(room_jid, contacts):
215 if self.host.whoami:
216 nick = self.host.whoami.node
217 if room_jid not in [room.bare for room in self.host.room_list]:
218 self.host.bridge.call('joinMUC', lambda room_jid: invite(room_jid, contacts), room_jid, nick)
219 else:
220 self.host.getOrCreateLiberviaWidget(panels.ChatPanel, (room_jid, "group"), True, JID(room_jid).bare)
221 invite(room_jid, contacts)
222
223 dialog.RoomAndContactsChooser(self.host, join, ok_button="Join", visible=(True, False))
224
225 def onCollectiveRadio(self):
226 def callback(room_jid, contacts):
227 self.host.bridge.call('launchRadioCollective', None, contacts, room_jid)
228 dialog.RoomAndContactsChooser(self.host, callback, ok_button="Choose", title="Collective Radio", visible=(False, True))
229
230 #Game menu
231 def onTarotGame(self):
232 def onPlayersSelected(room_jid, other_players):
233 self.host.bridge.call('launchTarotGame', None, other_players, room_jid)
234 dialog.RoomAndContactsChooser(self.host, onPlayersSelected, 3, title="Tarot", title_invite="Please select 3 other players", visible=(False, True))
235
236 def onXiangqiGame(self):
237 Window.alert("A Xiangqi game is planed, but not available yet")
238
239 #Settings menu
240
241 def onAccount(self):
242 def gotUI(xmlui):
243 if not xmlui:
244 return
245 body = XMLUI(self.host, xmlui)
246 _dialog = dialog.GenericDialog("Manage your XMPP account", body, options=['NO_CLOSE'])
247 body.setCloseCb(_dialog.close)
248 _dialog.show()
249 self.host.bridge.call('getAccountDialogUI', gotUI)
250
251 def onParameters(self):
252 def gotParams(xmlui):
253 if not xmlui:
254 return
255 body = XMLUI(self.host, xmlui)
256 _dialog = dialog.GenericDialog("Parameters", body, options=['NO_CLOSE'])
257 body.setCloseCb(_dialog.close)
258 _dialog.setSize('80%', '80%')
259 _dialog.show()
260 self.host.bridge.call('getParamsUI', gotParams)
261
262 def removeItemParams(self):
263 """Remove the Parameters item from the Settings menu bar."""
264 self.menu_settings.removeItem(self.item_params)
265
266 def onAvatarUpload(self):
267 body = AvatarUpload()
268 _dialog = dialog.GenericDialog("Avatar upload", body, options=['NO_CLOSE'])
269 body.setCloseCb(_dialog.close)
270 _dialog.setWidth('40%')
271 _dialog.show()