comparison frontends/src/primitivus/chat.py @ 1382:b01efa1c0f5e

quick_frontend, primitivus: better PEP-8 compliance + remove/rename some (Quick)Chat attributes: - remove QuickChat.id, use QuickChat.target instead - rename Chat.present_panel to Chat.occupants_panel - rename Chat.present_wid to Chat.occupants_list
author souliane <souliane@mailoo.org>
date Sun, 22 Mar 2015 14:20:19 +0100
parents 3dae6964c071
children 59c48796759e
comparison
equal deleted inserted replaced
1381:0d12d4e32664 1382:b01efa1c0f5e
50 return True 50 return True
51 51
52 def keypress(self, size, key): 52 def keypress(self, size, key):
53 return key 53 return key
54 54
55 def rows(self,size,focus=False): 55 def rows(self, size, focus=False):
56 return self.display_widget(size, focus).rows(size, focus) 56 return self.display_widget(size, focus).rows(size, focus)
57 57
58 def render(self, size, focus=False): 58 def render(self, size, focus=False):
59 canvas = urwid.CompositeCanvas(self.display_widget(size, focus).render(size, focus)) 59 canvas = urwid.CompositeCanvas(self.display_widget(size, focus).render(size, focus))
60 if focus: 60 if focus:
61 canvas.set_cursor(self.get_cursor_coords(size)) 61 canvas.set_cursor(self.get_cursor_coords(size))
62 return canvas 62 return canvas
63 63
64 def get_cursor_coords(self, size): 64 def get_cursor_coords(self, size):
65 #(maxcol,) = size
66 return 0, 0 65 return 0, 0
67 66
68 def display_widget(self, size, focus): 67 def display_widget(self, size, focus):
69 render_txt = [] 68 render_txt = []
70 if not self.is_info: 69 if not self.is_info:
71 if self.parent.show_timestamp: 70 if self.parent.show_timestamp:
72 time_format = "%c" if self.timestamp < self.parent.day_change else "%H:%M" #if the message was sent before today, we print the full date 71 time_format = "%c" if self.timestamp < self.parent.day_change else "%H:%M" # if the message was sent before today, we print the full date
73 render_txt.append(('date',"[%s]" % time.strftime(time_format, self.timestamp).decode('utf-8'))) 72 render_txt.append(('date', "[%s]" % time.strftime(time_format, self.timestamp).decode('utf-8')))
74 if self.parent.show_short_nick: 73 if self.parent.show_short_nick:
75 render_txt.append(('my_nick' if self.my_mess else 'other_nick',"**" if self.my_mess else "*")) 74 render_txt.append(('my_nick' if self.my_mess else 'other_nick', "**" if self.my_mess else "*"))
76 else: 75 else:
77 render_txt.append(('my_nick' if self.my_mess else 'other_nick',"[%s] " % self.nick)) 76 render_txt.append(('my_nick' if self.my_mess else 'other_nick', "[%s] " % self.nick))
78 render_txt.append(self.message) 77 render_txt.append(self.message)
79 txt_widget = urwid.Text(render_txt, align=self.align) 78 txt_widget = urwid.Text(render_txt, align=self.align)
80 if self.is_info: 79 if self.is_info:
81 return urwid.AttrMap(txt_widget, 'info_msg') 80 return urwid.AttrMap(txt_widget, 'info_msg')
82 return txt_widget 81 return txt_widget
97 # we must adapt the behaviour with the type 96 # we must adapt the behaviour with the type
98 if type_ == C.CHAT_ONE2ONE: 97 if type_ == C.CHAT_ONE2ONE:
99 self.historyPrint(profile=self.profile) 98 self.historyPrint(profile=self.profile)
100 elif type_ == C.CHAT_GROUP: 99 elif type_ == C.CHAT_GROUP:
101 if len(self.chat_colums.contents) == 1: 100 if len(self.chat_colums.contents) == 1:
102 present_widget = self._buildPresentList() 101 self.occupants_list = sat_widgets.GenericList([], option_type=sat_widgets.ClickableText, on_click=self._occupantsClicked)
103 self.present_panel = sat_widgets.VerticalSeparator(present_widget) 102 self.occupants_panel = sat_widgets.VerticalSeparator(self.occupants_list)
104 self._appendPresentPanel() 103 self._appendOccupantsPanel()
105 104
106 self.day_change = time.strptime(time.strftime("%a %b %d 00:00:00 %Y")) #struct_time of day changing time 105 self.day_change = time.strptime(time.strftime("%a %b %d 00:00:00 %Y")) # struct_time of day changing time
107 self.show_timestamp = True 106 self.show_timestamp = True
108 self.show_short_nick = False 107 self.show_short_nick = False
109 self.show_title = 1 #0: clip title; 1: full title; 2: no title 108 self.show_title = 1 # 0: clip title; 1: full title; 2: no title
110 self.subject = None 109 self.subject = None
111 110
112 def keypress(self, size, key): 111 def keypress(self, size, key):
113 if key == a_key['OCCUPANTS_HIDE']: #user wants to (un)hide the presents panel 112 if key == a_key['OCCUPANTS_HIDE']: # user wants to (un)hide the occupants panel
114 if self.type == C.CHAT_GROUP: 113 if self.type == C.CHAT_GROUP:
115 widgets = [widget for (widget, options) in self.chat_colums.contents] 114 widgets = [widget for (widget, options) in self.chat_colums.contents]
116 if self.present_panel in widgets: 115 if self.occupants_panel in widgets:
117 self._removePresentPanel() 116 self._removeOccupantsPanel()
118 else: 117 else:
119 self._appendPresentPanel() 118 self._appendOccupantsPanel()
120 elif key == a_key['TIMESTAMP_HIDE']: #user wants to (un)hide timestamp 119 elif key == a_key['TIMESTAMP_HIDE']: # user wants to (un)hide timestamp
121 self.show_timestamp = not self.show_timestamp 120 self.show_timestamp = not self.show_timestamp
122 for wid in self.content: 121 for wid in self.content:
123 wid._invalidate() 122 wid._invalidate()
124 elif key == a_key['SHORT_NICKNAME']: #user wants to (not) use short nick 123 elif key == a_key['SHORT_NICKNAME']: # user wants to (not) use short nick
125 self.show_short_nick = not self.show_short_nick 124 self.show_short_nick = not self.show_short_nick
126 for wid in self.content: 125 for wid in self.content:
127 wid._invalidate() 126 wid._invalidate()
128 elif key == a_key['SUBJECT_SWITCH']: #user wants to (un)hide group's subject or change its apperance 127 elif key == a_key['SUBJECT_SWITCH']: # user wants to (un)hide group's subject or change its apperance
129 if self.subject: 128 if self.subject:
130 self.show_title = (self.show_title + 1) % 3 129 self.show_title = (self.show_title + 1) % 3
131 if self.show_title == 0: 130 if self.show_title == 0:
132 self.setSubject(self.subject,'clip') 131 self.setSubject(self.subject, 'clip')
133 elif self.show_title == 1: 132 elif self.show_title == 1:
134 self.setSubject(self.subject,'space') 133 self.setSubject(self.subject, 'space')
135 elif self.show_title == 2: 134 elif self.show_title == 2:
136 self.chat_widget.header = None 135 self.chat_widget.header = None
137 self._invalidate() 136 self._invalidate()
138 137
139 return super(Chat, self).keypress(size, key) 138 return super(Chat, self).keypress(size, key)
154 """Set a MUC occupant's states. 153 """Set a MUC occupant's states.
155 154
156 @param occupant_jid (jid.JID): occupant to update 155 @param occupant_jid (jid.JID): occupant to update
157 @param states (dict{unicode: unicode}): new states 156 @param states (dict{unicode: unicode}): new states
158 """ 157 """
159 options = self.present_wid.getAllValues() 158 options = self.occupants_list.getAllValues()
160 for index in xrange(0, len(options)): 159 for index in xrange(0, len(options)):
161 nick = options[index].value 160 nick = options[index].value
162 if nick == occupant_jid.resource: 161 if nick == occupant_jid.resource:
163 options[index] = (nick, "%s %s" % (u''.join(states.values()), nick)) 162 options[index] = (nick, "%s %s" % (u''.join(states.values()), nick))
164 self.present_wid.changeValues(options) 163 self.occupants_list.changeValues(options)
165 break 164 break
166 self.host.redraw() 165 self.host.redraw()
167 166
168 def setContactStates(self, contact_jid, states): 167 def setContactStates(self, contact_jid, states):
169 """Set a one2one contact's states. 168 """Set a one2one contact's states.
172 @param states (dict{unicode: unicode}): new states 171 @param states (dict{unicode: unicode}): new states
173 """ 172 """
174 self.title_dynamic = ' '.join([u'({})'.format(state) for state in states.values()]) 173 self.title_dynamic = ' '.join([u'({})'.format(state) for state in states.values()])
175 self.host.redraw() 174 self.host.redraw()
176 175
177 def _presentClicked(self, list_wid, clicked_wid): 176 def _occupantsClicked(self, list_wid, clicked_wid):
178 assert self.type == C.CHAT_GROUP 177 assert self.type == C.CHAT_GROUP
179 nick = clicked_wid.getValue().value 178 nick = clicked_wid.getValue().value
180 if nick == self.getUserNick(): 179 if nick == self.getUserNick():
181 #We ignore clicks on our own nick 180 # We ignore clicks on our own nick
182 return 181 return
183 contact_list = self.host.contact_lists[self.profile] 182 contact_list = self.host.contact_lists[self.profile]
184 full_jid = jid.JID("%s/%s" % (self.target.bare, nick)) 183 full_jid = jid.JID("%s/%s" % (self.target.bare, nick))
185 184
186 #we have a click on a nick, we need to create the widget if it doesn't exists 185 # we have a click on a nick, we need to create the widget if it doesn't exists
187 self.getOrCreatePrivateWidget(full_jid) 186 self.getOrCreatePrivateWidget(full_jid)
188 187
189 #now we select the new window 188 # now we select the new window
190 contact_list.setFocus(full_jid, True) 189 contact_list.setFocus(full_jid, True)
191 190
192 def _buildPresentList(self): 191 def _appendOccupantsPanel(self):
193 self.present_wid = sat_widgets.GenericList([],option_type = sat_widgets.ClickableText, on_click=self._presentClicked) 192 self.chat_colums.contents.append((self.occupants_panel, ('weight', 2, False)))
194 return self.present_wid 193
195 194 def _removeOccupantsPanel(self):
196 def _appendPresentPanel(self):
197 self.chat_colums.contents.append((self.present_panel,('weight', 2, False)))
198
199 def _removePresentPanel(self):
200 for widget, options in self.chat_colums.contents: 195 for widget, options in self.chat_colums.contents:
201 if widget is self.present_panel: 196 if widget is self.occupants_panel:
202 self.chat_colums.contents.remove((widget, options)) 197 self.chat_colums.contents.remove((widget, options))
203 break 198 break
204 199
205 def addGamePanel(self, widget): 200 def addGamePanel(self, widget):
206 """Insert a game panel to this Chat dialog. 201 """Insert a game panel to this Chat dialog.
223 218
224 def setSubject(self, subject, wrap='space'): 219 def setSubject(self, subject, wrap='space'):
225 """Set title for a group chat""" 220 """Set title for a group chat"""
226 QuickChat.setSubject(self, subject) 221 QuickChat.setSubject(self, subject)
227 self.subject = subject 222 self.subject = subject
228 self.subj_wid = urwid.Text(unicode(subject.replace('\n','|') if wrap == 'clip' else subject ), 223 self.subj_wid = urwid.Text(unicode(subject.replace('\n', '|') if wrap == 'clip' else subject),
229 align='left' if wrap=='clip' else 'center',wrap=wrap) 224 align='left' if wrap == 'clip' else 'center', wrap=wrap)
230 self.chat_widget.header = urwid.AttrMap(self.subj_wid,'title') 225 self.chat_widget.header = urwid.AttrMap(self.subj_wid, 'title')
231 self.host.redraw() 226 self.host.redraw()
232 227
233 def addUser(self, param_nick): 228 def addUser(self, param_nick):
234 """Add user if it is not in the group list""" 229 """Add user if it is not in the group list"""
235 nick = unicode(param_nick) #FIXME: should be done in DBus bridge 230 nick = unicode(param_nick) # FIXME: should be done in DBus bridge
236 QuickChat.addUser(self, nick) 231 QuickChat.addUser(self, nick)
237 presents = self.present_wid.getAllValues() 232 occupants = self.occupants_list.getAllValues()
238 if nick not in [present.value for present in presents]: 233 if nick not in [occupants.value for occupants in occupants]:
239 presents.append(nick) 234 occupants.append(nick)
240 presents.sort(cmp=lambda a, b: cmp(a.value if hasattr(a, 'value') else a, b.value if hasattr(b, 'value') else b)) 235 occupants.sort(cmp=lambda a, b: cmp(a.value if hasattr(a, 'value') else a, b.value if hasattr(b, 'value') else b))
241 self.present_wid.changeValues(presents) 236 self.occupants_list.changeValues(occupants)
242 self.host.redraw() 237 self.host.redraw()
243 238
244 def removeUser(self, param_nick): 239 def removeUser(self, param_nick):
245 """Remove a user from the group list""" 240 """Remove a user from the group list"""
246 nick = unicode(param_nick) #FIXME: should be done in DBus bridge 241 nick = unicode(param_nick) # FIXME: should be done in DBus bridge
247 QuickChat.removeUser(self, nick) 242 QuickChat.removeUser(self, nick)
248 self.present_wid.deleteValue(nick) 243 self.occupants_list.deleteValue(nick)
249 self.host.redraw() 244 self.host.redraw()
250 245
251 def clearHistory(self): 246 def clearHistory(self):
252 """Clear the content of this chat.""" 247 """Clear the content of this chat."""
253 del self.content[:] 248 del self.content[:]
266 if extra is None: 261 if extra is None:
267 extra = {} 262 extra = {}
268 try: 263 try:
269 timestamp = float(extra['timestamp']) 264 timestamp = float(extra['timestamp'])
270 except KeyError: 265 except KeyError:
271 timestamp=None 266 timestamp = None
272 try: 267 try:
273 nick, mymess = QuickChat.printMessage(self, from_jid, msg, extra, profile) 268 nick, mymess = QuickChat.printMessage(self, from_jid, msg, extra, profile)
274 except TypeError: 269 except TypeError:
275 # None is returned, the message is managed 270 # None is returned, the message is managed
276 return 271 return
281 current_text = self.content[idx] 276 current_text = self.content[idx]
282 older = new_text.timestamp < current_text.timestamp 277 older = new_text.timestamp < current_text.timestamp
283 if older and idx > 0: 278 if older and idx > 0:
284 continue # the new message is older, we need to insert it upper 279 continue # the new message is older, we need to insert it upper
285 280
286 #we discard double messages, to avoid backlog / history conflict 281 # we discard double messages, to avoid backlog / history conflict
287 # FIXME: messages that have been sent several times will be displayed only once 282 # FIXME: messages that have been sent several times will be displayed only once
288 if ((idx and self.content[idx - 1].message == msg) or 283 if ((idx and self.content[idx - 1].message == msg) or
289 (self.content[idx].message == msg) or 284 (self.content[idx].message == msg) or
290 (idx < len(self.content) - 2 and self.content[idx + 1].message)): 285 (idx < len(self.content) - 2 and self.content[idx + 1].message)):
291 return 286 return
311 if extra is None: 306 if extra is None:
312 extra = {} 307 extra = {}
313 try: 308 try:
314 timestamp = float(extra['timestamp']) 309 timestamp = float(extra['timestamp'])
315 except KeyError: 310 except KeyError:
316 timestamp=None 311 timestamp = None
317 _widget = ChatText(self, timestamp, None, False, msg, is_info=True) 312 _widget = ChatText(self, timestamp, None, False, msg, is_info=True)
318 self.content.append(_widget) 313 self.content.append(_widget)
319 self._notify(msg=msg) 314 self._notify(msg=msg)
320 315
321 def _notify(self, from_jid="somebody", msg=""): 316 def _notify(self, from_jid="somebody", msg=""):
324 @param msg: the message that has been received 319 @param msg: the message that has been received
325 """ 320 """
326 if msg == "": 321 if msg == "":
327 return 322 return
328 if self.text_list.get_focus()[1] == len(self.content) - 2: 323 if self.text_list.get_focus()[1] == len(self.content) - 2:
329 #we don't change focus if user is not at the bottom 324 # we don't change focus if user is not at the bottom
330 #as that mean that he is probably watching discussion history 325 # as that mean that he is probably watching discussion history
331 self.text_list.focus_position = len(self.content) - 1 326 self.text_list.focus_position = len(self.content) - 1
332 self.host.redraw() 327 self.host.redraw()
333 if not self.host.x_notify.hasFocus(): 328 if not self.host.x_notify.hasFocus():
334 if self.type == C.CHAT_ONE2ONE: 329 if self.type == C.CHAT_ONE2ONE:
335 self.host.x_notify.sendNotification(_("Primitivus: %s is talking to you") % from_jid) 330 self.host.x_notify.sendNotification(_("Primitivus: %s is talking to you") % from_jid)
336 elif self.getUserNick().lower() in msg.lower(): 331 elif self.getUserNick().lower() in msg.lower():
337 self.host.x_notify.sendNotification(_("Primitivus: %(user)s mentioned you in room '%(room)s'") % {'user': from_jid, 'room': self.target}) 332 self.host.x_notify.sendNotification(_("Primitivus: %(user)s mentioned you in room '%(room)s'") % {'user': from_jid, 'room': self.target})
338 333
339 #MENU EVENTS# 334 # MENU EVENTS #
340 def onTarotRequest(self, menu): 335 def onTarotRequest(self, menu):
341 # TODO: move this to plugin_misc_tarot with dynamic menu 336 # TODO: move this to plugin_misc_tarot with dynamic menu
342 if len(self.occupants) != 4: 337 if len(self.occupants) != 4:
343 self.host.showPopUp(sat_widgets.Alert(_("Can't start game"), _("You need to be exactly 4 peoples in the room to start a Tarot game"), ok_cb=self.host.removePopUp)) 338 self.host.showPopUp(sat_widgets.Alert(_("Can't start game"), _("You need to be exactly 4 peoples in the room to start a Tarot game"), ok_cb=self.host.removePopUp))
344 else: 339 else:
345 self.host.bridge.tarotGameCreate(self.id, list(self.occupants), self.profile) 340 self.host.bridge.tarotGameCreate(self.target, list(self.occupants), self.profile)
346 341
347 def onSendFileRequest(self, menu): 342 def onSendFileRequest(self, menu):
348 # TODO: move this to core with dynamic menus 343 # TODO: move this to core with dynamic menus
349 dialog = FileDialog(ok_cb=self.onFileSelected, cancel_cb=self.host.removePopUp) 344 dialog = FileDialog(ok_cb=self.onFileSelected, cancel_cb=self.host.removePopUp)
350 self.host.showPopUp(dialog, 80, 80) 345 self.host.showPopUp(dialog, 80, 80)
351 346
352 #MISC EVENTS# 347 # MISC EVENTS #
353 def onFileSelected(self, filepath): 348 def onFileSelected(self, filepath):
354 self.host.removePopUp() 349 self.host.removePopUp()
355 try: 350 try:
356 filepath = filepath.decode('utf-8') # FIXME: correctly manage unicode 351 filepath = filepath.decode('utf-8') # FIXME: correctly manage unicode
357 except UnicodeError: 352 except UnicodeError:
358 log.error("FIXME: filepath with unicode error are not managed yet") 353 log.error("FIXME: filepath with unicode error are not managed yet")
359 self.host.showDialog(_(u"File has a unicode error in its name, it's not yet managed by SàT"), title=_("Can't send file"), type_="error") 354 self.host.showDialog(_(u"File has a unicode error in its name, it's not yet managed by SàT"), title=_("Can't send file"), type_="error")
360 return 355 return
361 #FIXME: check last_resource: what if self.target.resource exists ? 356 # FIXME: check last_resource: what if self.target.resource exists ?
362 last_resource = self.host.bridge.getMainResource(unicode(self.target.bare), self.profile) 357 last_resource = self.host.bridge.getMainResource(unicode(self.target.bare), self.profile)
363 if last_resource: 358 if last_resource:
364 full_jid = jid.JID("%s/%s" % (self.target.bare, last_resource)) 359 full_jid = jid.JID("%s/%s" % (self.target.bare, last_resource))
365 else: 360 else:
366 full_jid = self.target 361 full_jid = self.target
367 progress_id = self.host.bridge.sendFile(full_jid, filepath, {}, self.profile) 362 progress_id = self.host.bridge.sendFile(full_jid, filepath, {}, self.profile)
368 self.host.addProgress(progress_id,filepath) 363 self.host.addProgress(progress_id, filepath)
369 self.host.showDialog(_(u"You file request has been sent, we are waiting for your contact answer"), title=_("File request sent")) 364 self.host.showDialog(_(u"You file request has been sent, we are waiting for your contact answer"), title=_("File request sent"))
370 365
371 366
372 quick_widgets.register(QuickChat, Chat) 367 quick_widgets.register(QuickChat, Chat)
373 quick_widgets.register(quick_games.Tarot, game_tarot.TarotGame) 368 quick_widgets.register(quick_games.Tarot, game_tarot.TarotGame)