comparison browser_side/panels.py @ 202:2bc6cf004e61

browser, server: comments handling: - banner in unibar show a specific message when the message will be a comment - comments are inserted in a subpanel, in chronological order
author Goffi <goffi@goffi.org>
date Thu, 20 Jun 2013 12:16:46 +0200
parents aa76793da353
children 4d7054542751
comparison
equal deleted inserted replaced
201:aa76793da353 202:2bc6cf004e61
62 """This text box is used as a main typing point, for message, microblog, etc""" 62 """This text box is used as a main typing point, for message, microblog, etc"""
63 63
64 def __init__(self, host): 64 def __init__(self, host):
65 TextArea.__init__(self) 65 TextArea.__init__(self)
66 #AutoCompleteTextBox.__init__(self) 66 #AutoCompleteTextBox.__init__(self)
67 self.__size = (0,0) 67 self.__size = (0,0)
68 self._popup = None 68 self._popup = None
69 self._timer = Timer(notify=self._timeCb) 69 self._timer = Timer(notify=self._timeCb)
70 self.host = host 70 self.host = host
71 self.setStyleName('uniBox') 71 self.setStyleName('uniBox')
72 self.addKeyboardListener(self) 72 self.addKeyboardListener(self)
82 def removeKey(self, key): 82 def removeKey(self, key):
83 try: 83 try:
84 self.getCompletionItems().completions.remove(key) 84 self.getCompletionItems().completions.remove(key)
85 except KeyError: 85 except KeyError:
86 print "WARNING: trying to remove an unknown key" 86 print "WARNING: trying to remove an unknown key"
87 87
88 88
89 def showWarning(self, target_data): 89 def showWarning(self, target_data):
90 target_hook, _type, msg = target_data 90 target_hook, _type, msg = target_data
91 if _type == "NONE": 91 if _type == "NONE":
92 return 92 return
113 self._popup.setStyleName("warningPopup") 113 self._popup.setStyleName("warningPopup")
114 if style: 114 if style:
115 self._popup.addStyleName(style) 115 self._popup.addStyleName(style)
116 116
117 left = 0 117 left = 0
118 top = 0 #max(0, self.getAbsoluteTop() - contents.getOffsetHeight() - 2) 118 top = 0 #max(0, self.getAbsoluteTop() - contents.getOffsetHeight() - 2)
119 self._popup.setPopupPosition(left, top) 119 self._popup.setPopupPosition(left, top)
120 self._popup.show() 120 self._popup.show()
121 121
122 def _timeCb(self, timer): 122 def _timeCb(self, timer):
123 if self._popup: 123 if self._popup:
130 @return: a tuple (selected, target_type, target info) with: 130 @return: a tuple (selected, target_type, target info) with:
131 - target_hook: None if we use the selected widget, (msg, data) if we have a hook (e.g. "@@: " for a public blog), where msg is the parsed message (i.e. without the "hook key: "@@: bla" become ("bla", None)) 131 - target_hook: None if we use the selected widget, (msg, data) if we have a hook (e.g. "@@: " for a public blog), where msg is the parsed message (i.e. without the "hook key: "@@: bla" become ("bla", None))
132 - target_type: one of PUBLIC, GROUP, ONE2ONE, STATUS, MISC 132 - target_type: one of PUBLIC, GROUP, ONE2ONE, STATUS, MISC
133 - msg: HTML message which will appear in the privacy warning banner """ 133 - msg: HTML message which will appear in the privacy warning banner """
134 target = self._selected_cache 134 target = self._selected_cache
135 135
136 def getSelectedOrStatus(): 136 def getSelectedOrStatus():
137 if target: 137 if target:
138 _type, msg = target.getWarningData() 138 _type, msg = target.getWarningData()
139 target_hook = None # we use the selected widget, not a hook 139 target_hook = None # we use the selected widget, not a hook
140 else: 140 else:
145 if not txt.startswith('@'): 145 if not txt.startswith('@'):
146 target_hook, _type, msg = getSelectedOrStatus() 146 target_hook, _type, msg = getSelectedOrStatus()
147 elif txt.startswith('@@: '): 147 elif txt.startswith('@@: '):
148 _type = "PUBLIC" 148 _type = "PUBLIC"
149 msg = MicroblogPanel.warning_msg_public 149 msg = MicroblogPanel.warning_msg_public
150 target_hook = (txt[4:], None) 150 target_hook = (txt[4:], None)
151 elif txt.startswith('@'): 151 elif txt.startswith('@'):
152 _end = txt.find(': ') 152 _end = txt.find(': ')
153 if _end == -1: 153 if _end == -1:
154 target_hook, _type, msg = getSelectedOrStatus() 154 target_hook, _type, msg = getSelectedOrStatus()
155 else: 155 else:
163 msg = MicroblogPanel.warning_msg_group % group 163 msg = MicroblogPanel.warning_msg_group % group
164 target_hook = (txt[_end+2:], group) 164 target_hook = (txt[_end+2:], group)
165 else: 165 else:
166 print "ERROR: Unknown target" 166 print "ERROR: Unknown target"
167 target_hook, _type, msg = getSelectedOrStatus() 167 target_hook, _type, msg = getSelectedOrStatus()
168 168
169 return (target_hook, _type, msg) 169 return (target_hook, _type, msg)
170 170
171 def onBrowserEvent(self, event): 171 def onBrowserEvent(self, event):
172 #XXX: woraroung a pyjamas bug: self.currentEvent is not set 172 #XXX: woraroung a pyjamas bug: self.currentEvent is not set
173 # so the TextBox's cancelKey doens't work. This is a workaround 173 # so the TextBox's cancelKey doens't work. This is a workaround
214 214
215 def onSelectedChange(self, selected): 215 def onSelectedChange(self, selected):
216 self._selected_cache = selected 216 self._selected_cache = selected
217 217
218 """def complete(self): 218 """def complete(self):
219 219
220 #self.visible=False #XXX: self.visible is not unset in pyjamas when ENTER is pressed and a completion is done 220 #self.visible=False #XXX: self.visible is not unset in pyjamas when ENTER is pressed and a completion is done
221 #XXX: fixed directly on pyjamas, if the patch is accepted, no need to walk around this 221 #XXX: fixed directly on pyjamas, if the patch is accepted, no need to walk around this
222 return AutoCompleteTextBox.complete(self)""" 222 return AutoCompleteTextBox.complete(self)"""
223 223
224 class MicroblogItem(): 224 class MicroblogItem():
225 #XXX: should be moved in a separated module 225 #XXX: should be moved in a separated module
226 226
227 def __init__(self, data): 227 def __init__(self, data):
228 self.id = data['id'] 228 self.id = data['id']
229 self.type = data.get('type','main_item')
229 self.content = data['content'] 230 self.content = data['content']
230 self.author = data['author'] 231 self.author = data['author']
231 self.timestamp = float(data.get('timestamp',0)) #XXX: int doesn't work here 232 self.timestamp = float(data.get('timestamp',0)) #XXX: int doesn't work here
232 233 self.comments = data.get('comments', False)
234 if self.comments:
235 try:
236 self.comments_hash = (data['comments_service'], data['comments_node'])
237 self.comments_service = data['comments_service']
238 self.comments_node = data['comments_node']
239 except KeyError:
240 print "Warning: can't manage comment [%s], some keys are missing in microblog data (%s)" % (data["comments"], data.keys())
241 self.comments = False
242 if set(("service","node")).issubset(data.keys()):
243 self.service = data["service"]
244 self.node = data["node"]
245 self.hash = (self.service, self.node)
246
233 class MicroblogEntry(SimplePanel, ClickHandler): 247 class MicroblogEntry(SimplePanel, ClickHandler):
234 248
235 def __init__(self, blog_panel, mblog_entry): 249 def __init__(self, blog_panel, mblog_entry):
236 SimplePanel.__init__(self) 250 SimplePanel.__init__(self)
237 self._blog_panel = blog_panel 251 self._blog_panel = blog_panel
238 252
239 self.author = mblog_entry.author 253 self.author = mblog_entry.author
240 self.timestamp = mblog_entry.timestamp 254 self.timestamp = mblog_entry.timestamp
241 _datetime = datetime.fromtimestamp(mblog_entry.timestamp) 255 _datetime = datetime.fromtimestamp(mblog_entry.timestamp)
256 self.comments = mblog_entry.comments
242 257
243 self.panel = HTMLPanel(""" 258 self.panel = HTMLPanel("""
244 <div class='mb_entry_header'><span class='mb_entry_author'>%(author)s</span> on <span class='mb_entry_timestamp'>%(timestamp)s</span></div> 259 <div class='mb_entry_header'><span class='mb_entry_author'>%(author)s</span> on <span class='mb_entry_timestamp'>%(timestamp)s</span></div>
245 <div class="mb_entry_avatar" id='id_avatar'></div> 260 <div class="mb_entry_avatar" id='id_avatar'></div>
246 <div class="mb_entry_dialog"> 261 <div class="mb_entry_dialog">
259 274
260 def updateAvatar(self, new_avatar): 275 def updateAvatar(self, new_avatar):
261 """Change the avatar of the entry 276 """Change the avatar of the entry
262 @param new_avatar: path to the new image""" 277 @param new_avatar: path to the new image"""
263 self.avatar.setUrl(new_avatar) 278 self.avatar.setUrl(new_avatar)
264 279
265 def onClick(self, sender): 280 def onClick(self, sender):
266 print "microblog entry selected (author=%s)" % self.author 281 print "microblog entry selected (author=%s)" % self.author
267 self._blog_panel.setSelectedEntry(self) 282 self._blog_panel.setSelectedEntry(self if self.comments else None)
268 283
269 284
270 class MicroblogPanel(base_widget.LiberviaWidget): 285 class MicroblogPanel(base_widget.LiberviaWidget):
271 warning_msg_public = "This message will be PUBLIC and everybody will be able to see it, even people you don't know" 286 warning_msg_public = "This message will be PUBLIC and everybody will be able to see it, even people you don't know"
272 warning_msg_group = "This message will be published for all the people of the group <span class='warningTarget'>%s</span>" 287 warning_msg_group = "This message will be published for all the people of the group <span class='warningTarget'>%s</span>"
278 base_widget.LiberviaWidget.__init__(self, host, ", ".join(accepted_groups), selectable = True) 293 base_widget.LiberviaWidget.__init__(self, host, ", ".join(accepted_groups), selectable = True)
279 #base_widget.ScrollPanelWrapper.__init__(self) 294 #base_widget.ScrollPanelWrapper.__init__(self)
280 #DropCell.__init__(self) 295 #DropCell.__init__(self)
281 self.accepted_groups = accepted_groups 296 self.accepted_groups = accepted_groups
282 self.entries = {} 297 self.entries = {}
298 self.comments = {}
283 self.selected_entry = None 299 self.selected_entry = None
284 self.vpanel = VerticalPanel() 300 self.vpanel = VerticalPanel()
285 self.vpanel.setStyleName('microblogPanel') 301 self.vpanel.setStyleName('microblogPanel')
286 self.setWidget(self.vpanel) 302 self.setWidget(self.vpanel)
287 303
304 host.FillMicroblogPanel(_new_panel) 320 host.FillMicroblogPanel(_new_panel)
305 host.bridge.call('getMassiveLastMblogs', _new_panel.massiveInsert, 'ALL', [], 10) 321 host.bridge.call('getMassiveLastMblogs', _new_panel.massiveInsert, 'ALL', [], 10)
306 return _new_panel 322 return _new_panel
307 323
308 def getWarningData(self): 324 def getWarningData(self):
309 if not self.accepted_groups: 325 if self.selected_entry:
326 if not self.selected_entry.comments:
327 print ("ERROR: an item without comment is selected")
328 return ("NONE", None)
329 return ("PUBLIC", "This is a <span class='warningTarget'>comment</span> and keep the initial post visibility, so it is potentialy public")
330
331 elif not self.accepted_groups:
310 # we have a meta MicroblogPanel, we publish publicly 332 # we have a meta MicroblogPanel, we publish publicly
311 return ("PUBLIC", self.warning_msg_public) 333 return ("PUBLIC", self.warning_msg_public)
312 else: 334 else:
313 # we only accept one group at the moment 335 # we only accept one group at the moment
314 # FIXME: manage several groups 336 # FIXME: manage several groups
315 return ("GROUP", self.warning_msg_group % self.accepted_groups[0]) 337 return ("GROUP", self.warning_msg_group % self.accepted_groups[0])
316 338
317 def onTextEntered(self, text): 339 def onTextEntered(self, text):
318 if not self.accepted_groups: 340 if self.selected_entry:
341 # we are entering a comment
342 comments_node = self.selected_entry.comments
343 if not comments_node:
344 raise Exception("ERROR: comments node is empty")
345 self.host.bridge.call("sendMblogComment", None, comments_node, text)
346 elif not self.accepted_groups:
347 # we are entering a public microblog
319 self.host.bridge.call("sendMblog", None, "PUBLIC", None, text) 348 self.host.bridge.call("sendMblog", None, "PUBLIC", None, text)
320 else: 349 else:
350 # we are entering a microblog restricted to a group
321 # FIXME: manage several groups 351 # FIXME: manage several groups
322 self.host.bridge.call("sendMblog", None, "GROUP", self.accepted_groups[0], text) 352 self.host.bridge.call("sendMblog", None, "GROUP", self.accepted_groups[0], text)
323 353
324 def accept_all(self): 354 def accept_all(self):
325 return not self.accepted_groups #we accept every microblog only if we are not filtering by groups 355 return not self.accepted_groups #we accept every microblog only if we are not filtering by groups
326 356
327 def getEntries(self): 357 def getEntries(self):
328 """Ask all the entries for the currenly accepted groups, 358 """Ask all the entries for the currenly accepted groups,
329 and fill the panel""" 359 and fill the panel"""
330 360
331 def massiveInsert(self, mblogs): 361 def massiveInsert(self, mblogs):
332 """Insert several microblogs at once 362 """Insert several microblogs at once
333 @param mblogs: dictionary of microblogs, as the result of getMassiveLastGroupBlogs 363 @param mblogs: dictionary of microblogs, as the result of getMassiveLastGroupBlogs
334 """ 364 """
335 print "Massive insertion of microblogs" 365 print "Massive insertion of microblogs"
336 for publisher in mblogs: 366 for publisher in mblogs:
337 print "adding blogs for [%s]" % publisher 367 print "adding blogs for [%s]" % publisher
338 for mblog in mblogs[publisher]: 368 for mblog in mblogs[publisher]:
339 if not mblog.has_key('content'): 369 if not "content" in mblog:
340 print ("WARNING: No content found in microblog [%s]", mblog) 370 print ("WARNING: No content found in microblog [%s]", mblog)
341 continue 371 continue
342 mblog_entry = MicroblogItem(mblog) 372 mblog_item = MicroblogItem(mblog)
343 self.addEntry(mblog_entry) 373 self.addEntry(mblog_item)
344 374
345 def addEntry(self, mblog_entry): 375 def mblogsInsert(self, mblogs):
346 """Add an entry to the panel 376 """ Insert several microblogs at once
347 @param mblog_entry: MicroblogItem instance 377 @param mblogs: list of microblogs
348 """ 378 """
349 if mblog_entry.id in self.entries: 379 for mblog in mblogs:
350 return 380 if not "content" in mblog:
351 _entry = MicroblogEntry(self, mblog_entry) 381 print ("WARNING: No content found in microblog [%s]", mblog)
352 self.entries[mblog_entry.id] = _entry 382 continue
353 383 mblog_item = MicroblogItem(mblog)
384 self.addEntry(mblog_item)
385
386 def _chronoInsert(self, vpanel, entry, reverse = True):
387 """ Insert an entry in chronological order
388 @param vpanel: VerticalPanel instance
389 @param entry: MicroblogEntry
390 @param reverse: more recent entry on top if True, chronological order else"""
354 # we look for the right index to insert our entry: 391 # we look for the right index to insert our entry:
355 # we insert the entry above the first entry 392 # if reversed, we insert the entry above the first entry
356 # in the past 393 # in the past
357 idx = 0 394 idx = 0
358 for child in self.vpanel.children: 395
396 for child in vpanel.children:
359 if not isinstance(child, MicroblogEntry): 397 if not isinstance(child, MicroblogEntry):
360 break 398 idx+=1
361 if child.timestamp < mblog_entry.timestamp: 399 continue
362 break 400 if reverse:
401 if child.timestamp < entry.timestamp:
402 break
403 else:
404 if child.timestamp > entry.timestamp:
405 break
363 idx+=1 406 idx+=1
364 self.vpanel.insert(_entry,idx) 407
408 vpanel.insert(entry, idx)
409
410 def addEntry(self, mblog_item):
411 """Add an entry to the panel
412 @param mblog_item: MicroblogItem instance
413 """
414 if mblog_item.type == "comment":
415 if not mblog_item.hash in self.comments:
416 # The comments node is not known in this panel
417 return
418 _entry = MicroblogEntry(self, mblog_item)
419 parent = self.comments[mblog_item.hash]
420 parent_idx = self.vpanel.getWidgetIndex(parent)
421 # we find or create the panel where the comment must be inserted
422 try:
423 sub_panel = self.vpanel.getWidget(parent_idx+1)
424 except IndexError:
425 sub_panel = None
426 if not sub_panel or not isinstance(sub_panel, VerticalPanel):
427 sub_panel = VerticalPanel()
428 sub_panel.setStyleName('microblogPanel')
429 sub_panel.addStyleName('subPanel')
430 self.vpanel.insert(sub_panel, parent_idx+1)
431
432 # we want comments to be inserted in chronological order
433 self._chronoInsert(sub_panel, _entry, reverse=False)
434 return
435
436 if mblog_item.id in self.entries:
437 return
438 _entry = MicroblogEntry(self, mblog_item)
439
440 self.entries[mblog_item.id] = _entry
441
442 self._chronoInsert(self.vpanel, _entry)
443
444 if mblog_item.comments:
445 # entry has comments, we keep the comment node as a reference
446 self.comments[mblog_item.comments_hash] = _entry
447 self.host.bridge.call('getMblogComments', self.mblogsInsert, mblog_item.comments_service, mblog_item.comments_node)
365 448
366 def setSelectedEntry(self, entry): 449 def setSelectedEntry(self, entry):
367 if self.selected_entry == entry: 450 if self.selected_entry == entry:
368 entry = None 451 entry = None
369 if self.selected_entry: 452 if self.selected_entry:
376 def updateValue(self, type, jid, value): 459 def updateValue(self, type, jid, value):
377 """Update a jid value in entries 460 """Update a jid value in entries
378 @param type: one of 'avatar', 'nick' 461 @param type: one of 'avatar', 'nick'
379 @param jid: jid concerned 462 @param jid: jid concerned
380 @param value: new value""" 463 @param value: new value"""
464 def updateVPanel(vpanel):
465 for child in vpanel.children:
466 if isinstance(child, MicroblogEntry) and child.author == jid:
467 child.updateAvatar(value)
468 elif isinstance(child, VerticalPanel):
469 updateVPanel(child)
381 if type=='avatar': 470 if type=='avatar':
382 for entry in self.entries.values(): 471 updateVPanel(self.vpanel)
383 if entry.author == jid:
384 entry.updateAvatar(value)
385 472
386 def setAcceptedGroup(self, group): 473 def setAcceptedGroup(self, group):
387 """Set the group which can be displayed in this panel 474 """Set the group which can be displayed in this panel
388 @param group: string of the group, or list of string 475 @param group: string of the group, or list of string
389 """ 476 """
464 def removeOccupant(self, nick): 551 def removeOccupant(self, nick):
465 try: 552 try:
466 self.remove(self.occupants_list[nick]) 553 self.remove(self.occupants_list[nick])
467 except KeyError: 554 except KeyError:
468 print "ERROR: trying to remove an unexisting nick" 555 print "ERROR: trying to remove an unexisting nick"
469 556
470 def clear(self): 557 def clear(self):
471 self.occupants_list.clear() 558 self.occupants_list.clear()
472 AbsolutePanel.clear(self) 559 AbsolutePanel.clear(self)
473 560
474 class ChatPanel(base_widget.LiberviaWidget): 561 class ChatPanel(base_widget.LiberviaWidget):
541 628
542 def onQuit(self): 629 def onQuit(self):
543 base_widget.LiberviaWidget.onQuit(self) 630 base_widget.LiberviaWidget.onQuit(self)
544 if self.type == 'group': 631 if self.type == 'group':
545 self.host.bridge.call('mucLeave', None, self.target.bare) 632 self.host.bridge.call('mucLeave', None, self.target.bare)
546 633
547 634
548 def setUserNick(self, nick): 635 def setUserNick(self, nick):
549 """Set the nick of the user, usefull for e.g. change the color of the user""" 636 """Set the nick of the user, usefull for e.g. change the color of the user"""
550 self.nick = nick 637 self.nick = nick
551 638
552 def setPresents(self, nicks): 639 def setPresents(self, nicks):
553 """Set the users presents in this room 640 """Set the users presents in this room
554 @param occupants: list of nicks (string)""" 641 @param occupants: list of nicks (string)"""
555 self.occupants_list.clear() 642 self.occupants_list.clear()
556 for nick in nicks: 643 for nick in nicks:
569 def getHistoryCB(history): 656 def getHistoryCB(history):
570 for line in history: 657 for line in history:
571 timestamp, from_jid, to_jid, message, mess_type = line 658 timestamp, from_jid, to_jid, message, mess_type = line
572 self.printMessage(from_jid, message, timestamp) 659 self.printMessage(from_jid, message, timestamp)
573 self.host.bridge.call('getHistory', getHistoryCB, self.host.whoami.bare, self.target.bare, size, True) 660 self.host.bridge.call('getHistory', getHistoryCB, self.host.whoami.bare, self.target.bare, size, True)
574 661
575 def printInfo(self, msg, type='normal'): 662 def printInfo(self, msg, type='normal'):
576 """Print general info 663 """Print general info
577 @param msg: message to print 664 @param msg: message to print
578 @type: one of: 665 @type: one of:
579 normal: general info like "toto has joined the room" 666 normal: general info like "toto has joined the room"
585 elif type == 'me': 672 elif type == 'me':
586 _wid.setStyleName('chatTextMe') 673 _wid.setStyleName('chatTextMe')
587 else: 674 else:
588 _wid.setStyleName('chatTextInfo') 675 _wid.setStyleName('chatTextInfo')
589 self.content.add(_wid) 676 self.content.add(_wid)
590 677
591 678
592 def printMessage(self, from_jid, msg, timestamp=None): 679 def printMessage(self, from_jid, msg, timestamp=None):
593 """Print message in chat window. Must be implemented by child class""" 680 """Print message in chat window. Must be implemented by child class"""
594 _jid=JID(from_jid) 681 _jid=JID(from_jid)
595 nick = _jid.node if self.type=='one2one' else _jid.resource 682 nick = _jid.node if self.type=='one2one' else _jid.resource
596 mymess = _jid.resource == self.nick if self.type == "group" else _jid.bare == self.host.whoami.bare #mymess = True if message comes from local user 683 mymess = _jid.resource == self.nick if self.type == "group" else _jid.bare == self.host.whoami.bare #mymess = True if message comes from local user
597 if msg.startswith('/me '): 684 if msg.startswith('/me '):
598 self.printInfo('* %s %s' % (nick, msg[4:]),type='me') 685 self.printInfo('* %s %s' % (nick, msg[4:]),type='me')
599 return 686 return
600 self.content.add(ChatText(timestamp, nick, mymess, msg)) 687 self.content.add(ChatText(timestamp, nick, mymess, msg))
601 self.content_scroll.scrollToBottom() 688 self.content_scroll.scrollToBottom()
602 689
603 def startGame(self, game_type, referee, players): 690 def startGame(self, game_type, referee, players):
604 """Configure the chat window to start a game""" 691 """Configure the chat window to start a game"""
605 if game_type=="Tarot": 692 if game_type=="Tarot":
606 if hasattr(self, "tarot_panel"): 693 if hasattr(self, "tarot_panel"):
607 return 694 return
610 self.vpanel.setCellHeight(self.tarot_panel, self.tarot_panel.getHeight()) 697 self.vpanel.setCellHeight(self.tarot_panel, self.tarot_panel.getHeight())
611 elif game_type=="RadioCol": 698 elif game_type=="RadioCol":
612 #XXX: We can have double panel if we join quickly enough to have the group chat start signal 699 #XXX: We can have double panel if we join quickly enough to have the group chat start signal
613 # on invitation + the one triggered on room join 700 # on invitation + the one triggered on room join
614 if hasattr(self, "radiocol_panel"): 701 if hasattr(self, "radiocol_panel"):
615 return 702 return
616 self.radiocol_panel = RadioColPanel(self, referee, self.nick) 703 self.radiocol_panel = RadioColPanel(self, referee, self.nick)
617 self.vpanel.insert(self.radiocol_panel, 0) 704 self.vpanel.insert(self.radiocol_panel, 0)
618 self.vpanel.setCellHeight(self.radiocol_panel, self.radiocol_panel.getHeight()) 705 self.vpanel.setCellHeight(self.radiocol_panel, self.radiocol_panel.getHeight())
619 706
620 def getGame(self, game_type): 707 def getGame(self, game_type):
621 """Return class managing the game type""" 708 """Return class managing the game type"""
622 #TODO: check that the game is launched, and manage errors 709 #TODO: check that the game is launched, and manage errors
623 if game_type=="Tarot": 710 if game_type=="Tarot":
624 return self.tarot_panel 711 return self.tarot_panel
625 elif game_type=="RadioCol": 712 elif game_type=="RadioCol":
626 return self.radiocol_panel 713 return self.radiocol_panel
627 714
628 class WebPanel(base_widget.LiberviaWidget): 715 class WebPanel(base_widget.LiberviaWidget):
629 """ (mini)browser like widget """ 716 """ (mini)browser like widget """
630 717
631 def __init__(self, host, url=None): 718 def __init__(self, host, url=None):
632 """ 719 """
633 @param host: SatWebFrontend instance 720 @param host: SatWebFrontend instance
634 """ 721 """
635 base_widget.LiberviaWidget.__init__(self, host) 722 base_widget.LiberviaWidget.__init__(self, host)
656 def onUrlClick(self, sender): 743 def onUrlClick(self, sender):
657 self._frame.setUrl(self._url.getText()) 744 self._frame.setUrl(self._url.getText())
658 745
659 class ContactTabPanel(HorizontalPanel): 746 class ContactTabPanel(HorizontalPanel):
660 """ TabPanel with a contacts list which can be hidden """ 747 """ TabPanel with a contacts list which can be hidden """
661 748
662 def __init__(self, host, locked = False): 749 def __init__(self, host, locked = False):
663 self.host=host 750 self.host=host
664 HorizontalPanel.__init__(self) 751 HorizontalPanel.__init__(self)
665 self._left = VerticalPanel() 752 self._left = VerticalPanel()
666 contacts_switch = Button('<<', self._contactsSwitch) 753 contacts_switch = Button('<<', self._contactsSwitch)
689 menu = Menu(host) 776 menu = Menu(host)
690 777
691 #unibox 778 #unibox
692 unibox_panel = UniBoxPanel(host) 779 unibox_panel = UniBoxPanel(host)
693 self.host.setUniBox(unibox_panel.unibox) 780 self.host.setUniBox(unibox_panel.unibox)
694 781
695 #status bar 782 #status bar
696 status = host.status_panel 783 status = host.status_panel
697 784
698 #contacts 785 #contacts
699 _contacts = VerticalPanel() 786 _contacts = VerticalPanel()
700 contacts_switch = Button('<<', self._contactsSwitch) 787 contacts_switch = Button('<<', self._contactsSwitch)
701 contacts_switch.addStyleName('contactsSwitch') 788 contacts_switch.addStyleName('contactsSwitch')
702 _contacts.add(contacts_switch) 789 _contacts.add(contacts_switch)
717 804
718 _hpanel = HorizontalPanel() 805 _hpanel = HorizontalPanel()
719 _hpanel.add(_contacts) 806 _hpanel.add(_contacts)
720 _hpanel.add(self.tab_panel) 807 _hpanel.add(self.tab_panel)
721 self.add(_hpanel) 808 self.add(_hpanel)
722 809
723 self.setWidth("100%") 810 self.setWidth("100%")
724 Window.addWindowResizeListener(self) 811 Window.addWindowResizeListener(self)
725 812
726 def _contactsSwitch(self, btn): 813 def _contactsSwitch(self, btn):
727 """ (Un)hide contacts panel """ 814 """ (Un)hide contacts panel """