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 = '&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.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