Mercurial > libervia-web
comparison src/browser/sat_browser/main_panel.py @ 679:a90cc8fc9605
merged branch frontends_multi_profiles
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 18 Mar 2015 16:15:18 +0100 |
parents | src/browser/sat_browser/panels.py@3eb3a2c0c011 src/browser/sat_browser/panels.py@849ffb24d5bf |
children | e876f493dccc |
comparison
equal
deleted
inserted
replaced
590:1bffc4c244c3 | 679:a90cc8fc9605 |
---|---|
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 """Panels used as main basis""" | |
21 | |
22 import pyjd # this is dummy in pyjs | |
23 from sat.core.log import getLogger | |
24 log = getLogger(__name__) | |
25 | |
26 from sat.core.i18n import _ | |
27 from sat_frontends.tools.strings import addURLToText | |
28 | |
29 from pyjamas.ui.DockPanel import DockPanel | |
30 from pyjamas.ui.HorizontalPanel import HorizontalPanel | |
31 from pyjamas.ui.VerticalPanel import VerticalPanel | |
32 from pyjamas.ui.Button import Button | |
33 from pyjamas.ui.HTML import HTML | |
34 from pyjamas.ui.ClickListener import ClickHandler | |
35 from pyjamas.Timer import Timer | |
36 from pyjamas.ui import HasVerticalAlignment | |
37 | |
38 | |
39 import menu | |
40 import dialog | |
41 import base_widget | |
42 import base_menu | |
43 import libervia_widget | |
44 import editor_widget | |
45 import contact_list | |
46 from constants import Const as C | |
47 | |
48 | |
49 ### Warning notification (visibility of message, and other warning data) ### | |
50 | |
51 | |
52 class WarningPopup(): | |
53 | |
54 def __init__(self): | |
55 self._popup = None | |
56 self._timer = Timer(notify=self._timeCb) | |
57 | |
58 def showWarning(self, type_=None, msg=None, duration=2000): | |
59 """Display a popup information message, e.g. to notify the recipient of a message being composed. | |
60 If type_ is None, a popup being currently displayed will be hidden. | |
61 @type_: a type determining the CSS style to be applied (see _showWarning) | |
62 @msg: message to be displayed | |
63 """ | |
64 if type_ is None: | |
65 self.__removeWarning() | |
66 return | |
67 if not self._popup: | |
68 self._showWarning(type_, msg) | |
69 elif (type_, msg) != self._popup.target_data: | |
70 self._timeCb(None) # we remove the popup | |
71 self._showWarning(type_, msg) | |
72 | |
73 self._timer.schedule(duration) | |
74 | |
75 def _showWarning(self, type_, msg): | |
76 """Display a popup information message, e.g. to notify the recipient of a message being composed. | |
77 @type_: a type determining the CSS style to be applied. For now the defined styles are | |
78 "NONE" (will do nothing), "PUBLIC", "GROUP", "STATUS" and "ONE2ONE". | |
79 @msg: message to be displayed | |
80 """ | |
81 if type_ == "NONE": | |
82 return | |
83 if not msg: | |
84 log.warning("no msg set uniBox warning") | |
85 return | |
86 if type_ == "PUBLIC": | |
87 style = "targetPublic" | |
88 elif type_ == "GROUP": | |
89 style = "targetGroup" | |
90 elif type_ == "STATUS": | |
91 style = "targetStatus" | |
92 elif type_ == "ONE2ONE": | |
93 style = "targetOne2One" | |
94 else: | |
95 log.error("unknown message type") | |
96 return | |
97 contents = HTML(msg) | |
98 | |
99 self._popup = dialog.PopupPanelWrapper(autoHide=False, modal=False) | |
100 self._popup.target_data = (type_, msg) | |
101 self._popup.add(contents) | |
102 self._popup.setStyleName("warningPopup") | |
103 if style: | |
104 self._popup.addStyleName(style) | |
105 | |
106 left = 0 | |
107 top = 0 # max(0, self.getAbsoluteTop() - contents.getOffsetHeight() - 2) | |
108 self._popup.setPopupPosition(left, top) | |
109 self._popup.show() | |
110 | |
111 def _timeCb(self, timer): | |
112 if self._popup: | |
113 self._popup.hide() | |
114 del self._popup | |
115 self._popup = None | |
116 | |
117 def __removeWarning(self): | |
118 """Remove the popup""" | |
119 self._timeCb(None) | |
120 | |
121 | |
122 ### Status ### | |
123 | |
124 | |
125 class StatusPanel(editor_widget.HTMLTextEditor): | |
126 | |
127 EMPTY_STATUS = '<click to set a status>' | |
128 | |
129 def __init__(self, host, status=''): | |
130 self.host = host | |
131 modifiedCb = lambda content: self.host.bridge.call('setStatus', None, self.host.presence_status_panel.presence, content['text']) or True | |
132 editor_widget.HTMLTextEditor.__init__(self, {'text': status}, modifiedCb, options={'no_xhtml': True, 'listen_focus': True, 'listen_click': True}) | |
133 self.edit(False) | |
134 self.setStyleName('marginAuto') | |
135 | |
136 @property | |
137 def status(self): | |
138 return self._original_content['text'] | |
139 | |
140 def __cleanContent(self, content): | |
141 status = content['text'] | |
142 if status == self.EMPTY_STATUS or status in C.PRESENCE.values(): | |
143 content['text'] = '' | |
144 return content | |
145 | |
146 def getContent(self): | |
147 return self.__cleanContent(editor_widget.HTMLTextEditor.getContent(self)) | |
148 | |
149 def setContent(self, content): | |
150 content = self.__cleanContent(content) | |
151 editor_widget.BaseTextEditor.setContent(self, content) | |
152 | |
153 def setDisplayContent(self): | |
154 status = self._original_content['text'] | |
155 try: | |
156 presence = self.host.presence_status_panel.presence | |
157 except AttributeError: # during initialization | |
158 presence = None | |
159 if not status: | |
160 if presence and presence in C.PRESENCE: | |
161 status = C.PRESENCE[presence] | |
162 else: | |
163 status = self.EMPTY_STATUS | |
164 self.display.setHTML(addURLToText(status)) | |
165 | |
166 | |
167 class PresenceStatusMenuBar(base_widget.WidgetMenuBar): | |
168 def __init__(self, parent): | |
169 styles = {'menu_bar': 'presence-button'} | |
170 base_widget.WidgetMenuBar.__init__(self, parent, parent.host, styles=styles) | |
171 self.button = self.addCategory(u"◉") | |
172 presence_menu = self.button.getSubMenu() | |
173 for presence, presence_i18n in C.PRESENCE.items(): | |
174 html = u'<span class="%s">◉</span> %s' % (contact_list.buildPresenceStyle(presence), presence_i18n) | |
175 presence_menu.addItem(html, True, base_menu.SimpleCmd(lambda presence=presence: self.changePresenceCb(presence))) | |
176 self.parent_panel = parent | |
177 | |
178 def changePresenceCb(self, presence=''): | |
179 """Callback to notice the backend of a new presence set by the user. | |
180 @param presence (unicode): the new presence is a value in ('', 'chat', 'away', 'dnd', 'xa') | |
181 """ | |
182 self.host.bridge.call('setStatus', None, presence, self.parent_panel.status_panel.status) | |
183 | |
184 @classmethod | |
185 def getCategoryHTML(cls, menu_name_i18n, type_): | |
186 return menu_name_i18n | |
187 | |
188 | |
189 class PresenceStatusPanel(HorizontalPanel, ClickHandler): | |
190 | |
191 def __init__(self, host, presence="", status=""): | |
192 self.host = host | |
193 self.plugin_menu_context = [] | |
194 HorizontalPanel.__init__(self, Width='100%') | |
195 self.presence_bar = PresenceStatusMenuBar(self) | |
196 self.status_panel = StatusPanel(host, status=status) | |
197 self.setPresence(presence) | |
198 | |
199 panel = HorizontalPanel() | |
200 panel.add(self.presence_bar) | |
201 panel.add(self.status_panel) | |
202 panel.setCellVerticalAlignment(self.presence_bar, 'baseline') | |
203 panel.setCellVerticalAlignment(self.status_panel, 'baseline') | |
204 panel.setStyleName("presenceStatusPanel") | |
205 self.add(panel) | |
206 | |
207 self.status_panel.edit(False) | |
208 | |
209 ClickHandler.__init__(self) | |
210 self.addClickListener(self) | |
211 | |
212 @property | |
213 def presence(self): | |
214 return self._presence | |
215 | |
216 @property | |
217 def status(self): | |
218 return self.status_panel._original_content['text'] | |
219 | |
220 def setPresence(self, presence): | |
221 self._presence = presence | |
222 contact_list.setPresenceStyle(self.presence_bar.button, self._presence) | |
223 | |
224 def setStatus(self, status): | |
225 self.status_panel.setContent({'text': status}) | |
226 self.status_panel.setDisplayContent() | |
227 | |
228 def onClick(self, sender): | |
229 # As status is the default target of uniBar, we don't want to select anything if click on it | |
230 self.host.setSelected(None) | |
231 | |
232 | |
233 ### Panels managing the main area ### | |
234 | |
235 | |
236 class MainPanel(DockPanel): | |
237 """The panel which take the whole screen""" | |
238 | |
239 def __init__(self, host): | |
240 self.host = host | |
241 DockPanel.__init__(self, StyleName="mainPanel liberviaTabPanel") | |
242 | |
243 # menu and status panel | |
244 self.header = VerticalPanel(StyleName="header") | |
245 self.menu = menu.MainMenuBar(host) | |
246 self.header.add(self.menu) | |
247 | |
248 # contacts | |
249 self.contacts_switch = Button(u'«', self._contactsSwitch) | |
250 self.contacts_switch.addStyleName('contactsSwitch') | |
251 | |
252 # tab panel | |
253 self.tab_panel = libervia_widget.MainTabPanel(host) | |
254 self.tab_panel.addWidgetsTab(_(u"Discussions"), select=True, locked=True) | |
255 | |
256 # XXX: widget's addition order is important! | |
257 self.add(self.header, DockPanel.NORTH) | |
258 self.add(self.tab_panel, DockPanel.CENTER) | |
259 self.setCellWidth(self.tab_panel, '100%') | |
260 self.setCellHeight(self.tab_panel, '100%') | |
261 self.add(self.tab_panel.getTabBar(), DockPanel.SOUTH) | |
262 | |
263 def addContactList(self, contact_list): | |
264 self.add(self.contacts_switch, DockPanel.WEST) | |
265 self.add(contact_list, DockPanel.WEST) | |
266 | |
267 def addPresenceStatusPanel(self, panel): | |
268 self.header.add(panel) | |
269 self.header.setCellHeight(panel, '100%') | |
270 self.header.setCellVerticalAlignment(panel, HasVerticalAlignment.ALIGN_BOTTOM) | |
271 | |
272 def _contactsSwitch(self, btn=None): | |
273 """ (Un)hide contacts panel """ | |
274 if btn is None: | |
275 btn = self.contacts_switch | |
276 clist = self.host.contact_list | |
277 clist.setVisible(not clist.getVisible()) | |
278 btn.setText(u"«" if clist.getVisible() else u"»") | |
279 self.host.resize() | |
280 | |
281 def _contactsMove(self, parent): | |
282 """Move the contacts container (containing the contact list and | |
283 the "hide/show" button) to another parent, but always as the | |
284 first child position (insert at index 0). | |
285 """ | |
286 if self._contacts.getParent(): | |
287 if self._contacts.getParent() == parent: | |
288 return | |
289 self._contacts.removeFromParent() | |
290 parent.insert(self._contacts, 0) | |
291 | |
292 def refresh(self): | |
293 """Refresh the main panel""" | |
294 self.unibox_panel.refresh() | |
295 self.host.contact_panel.refresh() | |
296 | |
297 |