comparison src/browser/sat_browser/main_panel.py @ 648:6d3142b782c3 frontends_multi_profiles

browser_side: classes reorganisation: - moved widgets in dedicated modules (base, contact, editor, libervia) and a widget module for single classes - same thing for panels (base, main, contact) - libervia_widget mix main panels and widget and drag n drop for technical reasons (see comments) - renamed WebPanel to WebWidget
author Goffi <goffi@goffi.org>
date Thu, 26 Feb 2015 18:10:54 +0100
parents src/browser/sat_browser/panels.py@7113d40533d6
children 40c72f3b7638
comparison
equal deleted inserted replaced
647:e0021d571eef 648:6d3142b782c3
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.AbsolutePanel import AbsolutePanel
30 from pyjamas.ui.HorizontalPanel import HorizontalPanel
31 from pyjamas.ui.Button import Button
32 from pyjamas.ui.HTML import HTML
33 from pyjamas.ui.ClickListener import ClickHandler
34 from pyjamas.Timer import Timer
35 from pyjamas import Window
36 from __pyjamas__ import doc
37
38
39 import base_menu
40 import menu
41 import dialog
42 import base_widget
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 = '&lt;click to set a status&gt;'
128
129 def __init__(self, host, status=''):
130 self.host = host
131 modifiedCb = lambda content: self.host.bridge.call('setStatus', None, self.host.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('statusPanel')
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.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"◉", u"◉", '')
172 for presence, presence_i18n in C.PRESENCE.items():
173 html = u'<span class="%s">◉</span> %s' % (contact_list.buildPresenceStyle(presence), presence_i18n)
174 self.addMenuItem([u"◉", presence], [u"◉", html], '', base_menu.MenuCmd(self, 'changePresenceCb', presence), asHTML=True)
175 self.parent_panel = parent
176
177 def changePresenceCb(self, presence):
178 """Callback to notice the backend of a new presence set by the user.
179 @param presence (str): the new presence is a value in ('', 'chat', 'away', 'dnd', 'xa')
180 """
181 self.host.bridge.call('setStatus', None, presence, self.parent_panel.status_panel.status)
182
183 @classmethod
184 def getCategoryHTML(cls, menu_name_i18n, type_):
185 return menu_name_i18n
186
187
188 class PresenceStatusPanel(HorizontalPanel, ClickHandler):
189
190 def __init__(self, host, presence="", status=""):
191 self.host = host
192 HorizontalPanel.__init__(self, Width='100%')
193 self.menu = PresenceStatusMenuBar(self)
194 self.status_panel = StatusPanel(host, status=status)
195 self.setPresence(presence)
196
197 panel = HorizontalPanel()
198 panel.add(self.menu)
199 panel.add(self.status_panel)
200 panel.setCellVerticalAlignment(self.menu, 'baseline')
201 panel.setCellVerticalAlignment(self.status_panel, 'baseline')
202 panel.setStyleName("marginAuto")
203 self.add(panel)
204
205 self.status_panel.edit(False)
206
207 ClickHandler.__init__(self)
208 self.addClickListener(self)
209
210 @property
211 def presence(self):
212 return self._presence
213
214 @property
215 def status(self):
216 return self.status_panel._original_content['text']
217
218 def setPresence(self, presence):
219 self._presence = presence
220 contact_list.setPresenceStyle(self.menu.button, self._presence)
221
222 def setStatus(self, status):
223 self.status_panel.setContent({'text': status})
224 self.status_panel.setDisplayContent()
225
226 def onClick(self, sender):
227 # As status is the default target of uniBar, we don't want to select anything if click on it
228 self.host.setSelected(None)
229
230
231 ### Panels managing the main area ###
232
233
234 class MainPanel(AbsolutePanel):
235 """The panel which take the whole screen"""
236
237 def __init__(self, host):
238 self.host = host
239 AbsolutePanel.__init__(self)
240
241 # menu
242 self.menu = menu.MainMenuPanel(host)
243
244 # # unibox
245 # self.unibox_panel = UniBoxPanel(host)
246 # self.unibox_panel.setVisible(False)
247
248 # contacts
249 self._contacts = HorizontalPanel()
250 self._contacts.addStyleName('globalLeftArea')
251 self.contacts_switch = Button(u'«', self._contactsSwitch)
252 self.contacts_switch.addStyleName('contactsSwitch')
253 self._contacts.add(self.contacts_switch)
254
255 # tabs
256 self.tab_panel = libervia_widget.MainTabPanel(host)
257 self.tab_panel.addWidgetsTab(_(u"Discussions"), select=True, locked=True)
258
259 self.header = AbsolutePanel()
260 self.header.add(self.menu)
261 # self.header.add(self.unibox_panel)
262 self.header.add(self.host.status_panel)
263 self.header.setStyleName('header')
264 self.add(self.header)
265
266 self._hpanel = HorizontalPanel()
267 self._hpanel.add(self._contacts)
268 self._hpanel.add(self.tab_panel)
269 self.add(self._hpanel)
270
271 self.setWidth("100%")
272 Window.addWindowResizeListener(self)
273
274 def addContactList(self, contact_list):
275 self._contacts.add(contact_list)
276
277 def _contactsSwitch(self, btn=None):
278 """ (Un)hide contacts panel """
279 if btn is None:
280 btn = self.contacts_switch
281 clist = self.host.contact_list
282 clist.setVisible(not clist.getVisible())
283 btn.setText(u"«" if clist.getVisible() else u"»")
284 self.host.resize()
285
286 def _contactsMove(self, parent):
287 """Move the contacts container (containing the contact list and
288 the "hide/show" button) to another parent, but always as the
289 first child position (insert at index 0).
290 """
291 if self._contacts.getParent():
292 if self._contacts.getParent() == parent:
293 return
294 self._contacts.removeFromParent()
295 parent.insert(self._contacts, 0)
296
297 def onWindowResized(self, width, height):
298 _elts = doc().getElementsByClassName('gwt-TabBar')
299 if not _elts.length:
300 tab_bar_h = 0
301 else:
302 tab_bar_h = _elts.item(0).offsetHeight
303 ideal_height = Window.getClientHeight() - tab_bar_h
304 self.setHeight("%s%s" % (ideal_height, "px"))
305
306 def refresh(self):
307 """Refresh the main panel"""
308 self.unibox_panel.refresh()
309 self.host.contact_panel.refresh()
310
311