comparison browser_side/panels.py @ 312:b4781a350483

browser_side: display a "New message" button and add a "comment" icon for main entries in MicroblogPanel when the unibox is disabled
author souliane <souliane@mailoo.org>
date Mon, 30 Dec 2013 00:33:19 +0100
parents 3135ff840b8e
children 5ad70625867a
comparison
equal deleted inserted replaced
311:3135ff840b8e 312:b4781a350483
343 # XXX: should be moved in a separated module 343 # XXX: should be moved in a separated module
344 344
345 def __init__(self, data): 345 def __init__(self, data):
346 self.id = data['id'] 346 self.id = data['id']
347 self.type = data.get('type', 'main_item') 347 self.type = data.get('type', 'main_item')
348 self.content = data['content'] 348 self.empty = data.get('new', False)
349 self.xhtml = data.get('xhtml') 349 self.content = data.get('content', '')
350 self.xhtml = data.get('xhtml', '')
350 self.author = data['author'] 351 self.author = data['author']
351 self.updated = float(data.get('updated', 0)) # XXX: int doesn't work here 352 self.updated = float(data.get('updated', 0)) # XXX: int doesn't work here
352 try: 353 try:
353 self.published = float(data['published']) # XXX: int doesn't work here 354 self.published = float(data['published']) # XXX: int doesn't work here
354 except KeyError: 355 except KeyError:
355 self.published = self.updated 356 self.published = self.updated
356 self.comments = data.get('comments', False) 357 self.comments = data.get('comments', False)
357 if self.comments: 358 if self.empty and self.type == 'main_item':
359 self.service = self.node = None
360 self.hash = (self.service, self.node)
361 else:
358 try: 362 try:
359 self.comments_hash = (data['comments_service'], data['comments_node']) 363 self.service = data['comments_service'] if self.comments else data['service']
360 self.comments_service = data['comments_service'] 364 self.node = data['comments_node'] if self.comments else data['node']
361 self.comments_node = data['comments_node'] 365 self.hash = (self.service, self.node)
362 except KeyError: 366 except KeyError:
363 print "Warning: can't manage comment [%s], some keys are missing in microblog data (%s)" % (data["comments"], data.keys()) 367 logging.error("Warning: can't manage item [%s] some keys are missing in microblog data (%s)" % (self.id, data.keys()))
364 self.comments = False 368 self.comments = False
365 if set(("service", "node")).issubset(data.keys()):
366 # comment item
367 self.service = data["service"]
368 self.node = data["node"]
369 else:
370 # main item
371 try:
372 self.service = data['comments_service']
373 self.node = data['comments_node']
374 except KeyError:
375 logging.error("Main item %s is missing its comments information!" % self.id)
376 self.hash = (self.service, self.node)
377 369
378 370
379 class MicroblogEntry(SimplePanel, ClickHandler, FocusHandler, KeyboardHandler): 371 class MicroblogEntry(SimplePanel, ClickHandler, FocusHandler, KeyboardHandler):
380 372
381 def __init__(self, blog_panel, mblog_entry): 373 def __init__(self, blog_panel, data={}):
374 """
375 @param blog_panel: the parent panel
376 @param data: dict containing the blog item data, or a MicroblogItem instance.
377 """
378 if isinstance(data, MicroblogItem):
379 self._base_item = data
380 else:
381 self._base_item = MicroblogItem(data)
382 SimplePanel.__init__(self) 382 SimplePanel.__init__(self)
383 self._blog_panel = blog_panel 383 self._blog_panel = blog_panel
384 384
385 self.entry = mblog_entry
386 self.author = mblog_entry.author
387 self.updated = mblog_entry.updated
388 self.published = mblog_entry.published
389 self.comments = mblog_entry.comments
390 self.pub_data = (mblog_entry.hash[0], mblog_entry.hash[1], mblog_entry.id)
391
392 self.editable_content = [mblog_entry.xhtml, const.SYNTAX_XHTML] if mblog_entry.xhtml else [mblog_entry.content, None]
393
394 self.panel = FlowPanel() 385 self.panel = FlowPanel()
395 self.panel.setStyleName('mb_entry') 386 self.panel.setStyleName('mb_entry')
396 update_text = u" — ✍ " + "<span class='mb_entry_timestamp'>%s</span>" % datetime.fromtimestamp(self.updated) 387
397 header = HTMLPanel("""<div class='mb_entry_header'> 388 self.header = HTMLPanel('')
398 <span class='mb_entry_author'>%(author)s</span> on 389 self.panel.add(self.header)
399 <span class='mb_entry_timestamp'>%(published)s</span>%(updated)s 390
400 </div>""" % {'author': html_sanitize(self.author), 391 self.entry_actions = VerticalPanel()
401 'published': datetime.fromtimestamp(self.published), 392 self.entry_actions.setStyleName('mb_entry_actions')
402 'updated': update_text if self.published != self.updated else '' 393 self.panel.add(self.entry_actions)
403 }
404 )
405
406
407
408 self.panel.add(header)
409
410 if self.author == blog_panel.host.whoami.bare:
411 entry_delete_update = VerticalPanel()
412 entry_delete_update.setStyleName('mb_entry_delete_update')
413 self.delete_label = Label(u"✗")
414 self.delete_label.setTitle("Delete this message")
415 self.update_label = Label(u"✍")
416 self.update_label.setTitle("Edit this message")
417 entry_delete_update.add(self.delete_label)
418 entry_delete_update.add(self.update_label)
419 self.delete_label.addClickListener(self)
420 self.update_label.addClickListener(self)
421 self.panel.add(entry_delete_update)
422 else:
423 self.update_label = self.delete_label = None
424 394
425 entry_avatar = SimplePanel() 395 entry_avatar = SimplePanel()
426 entry_avatar.setStyleName('mb_entry_avatar') 396 entry_avatar.setStyleName('mb_entry_avatar')
427 self.avatar = Image(blog_panel.host.getAvatar(self.author)) 397 self.avatar = Image(self._blog_panel.host.getAvatar(self.author))
428 entry_avatar.add(self.avatar) 398 entry_avatar.add(self.avatar)
429 self.panel.add(entry_avatar) 399 self.panel.add(entry_avatar)
430 400
431 self.entry_dialog = SimplePanel() 401 self.entry_dialog = SimplePanel()
432 self.entry_dialog.setStyleName('mb_entry_dialog') 402 self.entry_dialog.setStyleName('mb_entry_dialog')
433 body = addURLToText(html_sanitize(mblog_entry.content)) if not mblog_entry.xhtml else mblog_entry.xhtml
434 self.bubble = HTML(body)
435 self.bubble.setStyleName("bubble")
436 self.entry_dialog.add(self.bubble)
437 self.panel.add(self.entry_dialog) 403 self.panel.add(self.entry_dialog)
438 404
439 self.editbox = None
440 self.add(self.panel) 405 self.add(self.panel)
441 ClickHandler.__init__(self) 406 ClickHandler.__init__(self)
442 self.addClickListener(self) 407 self.addClickListener(self)
443 408
444 def onWindowResized(self, width=None, height=None): 409 self.pub_data = (self.hash[0], self.hash[1], self.id)
445 """The listener is active when the text is being modified""" 410 self._setContent()
446 left = self.avatar.getAbsoluteLeft() + self.avatar.getOffsetWidth() 411
447 right = self.delete_label.getAbsoluteLeft() 412 def __getattr__(self, name):
448 ideal_width = right - left - 60 413 """This allows to directly use the attributes of MicroblogItem"""
449 self.entry_dialog.setWidth("%spx" % ideal_width) 414 if hasattr(self, name):
415 return self.__dict__[name]
416 else:
417 return getattr(self._base_item, name)
418
419 def _setContent(self):
420 """Actually set the entry content (header, icons, bubble...)"""
421 self.delete_label = self.update_label = self.comment_label = None
422 self.bubble = self.editbox = None
423 self._setHeader()
424 if self.empty:
425 self.editable_content = ['', const.SYNTAX_XHTML]
426 else:
427 self.editable_content = [self.xhtml, const.SYNTAX_XHTML] if self.xhtml else [self.content, None]
428 self.setEntryDialog()
429 self._setIcons()
430
431 def _setHeader(self):
432 """Set the entry header"""
433 if self.empty:
434 return
435 update_text = u" — ✍ " + "<span class='mb_entry_timestamp'>%s</span>" % datetime.fromtimestamp(self.updated)
436 self.header.setHTML("""<div class='mb_entry_header'>
437 <span class='mb_entry_author'>%(author)s</span> on
438 <span class='mb_entry_timestamp'>%(published)s</span>%(updated)s
439 </div>""" % {'author': html_sanitize(self.author),
440 'published': datetime.fromtimestamp(self.published),
441 'updated': update_text if self.published != self.updated else ''
442 }
443 )
444
445 def _setIcons(self):
446 """Set the entry icons (delete, update, comment)"""
447 if self.empty:
448 return
449
450 def addIcon(label, title):
451 label = Label(label)
452 label.setTitle(title)
453 label.addClickListener(self)
454 self.entry_actions.add(label)
455 return label
456
457 if self.author == self._blog_panel.host.whoami.bare:
458 self.delete_label = addIcon(u"✗", "Delete this message")
459 self.update_label = addIcon(u"✍", "Edit this message")
460 if self.comments:
461 self.comment_label = addIcon(u"↶", "Comment this message")
450 462
451 def updateAvatar(self, new_avatar): 463 def updateAvatar(self, new_avatar):
452 """Change the avatar of the entry 464 """Change the avatar of the entry
453 @param new_avatar: path to the new image""" 465 @param new_avatar: path to the new image"""
454 self.avatar.setUrl(new_avatar) 466 self.avatar.setUrl(new_avatar)
455 467
456 def onClick(self, sender): 468 def onClick(self, sender):
457 if sender == self: 469 if sender == self:
458 self._blog_panel.setSelectedEntry(self if self.comments else None) 470 self._blog_panel.setSelectedEntry(self if self.comments else None)
459 elif sender == self.update_label:
460 self._update()
461 elif sender == self.delete_label: 471 elif sender == self.delete_label:
462 self._delete() 472 self._delete()
473 elif sender == self.update_label:
474 self.setEntryDialog(edit=True)
475 elif sender == self.comment_label:
476 self._comment()
463 477
464 def onKeyUp(self, sender, keycode, modifiers): 478 def onKeyUp(self, sender, keycode, modifiers):
465 """Update is done when ENTER key is pressed within the raw editbox""" 479 """Update is done when ENTER key is pressed within the raw editbox"""
466 if sender != self.editbox or not self.editbox.getVisible(): 480 if sender != self.editbox or not self.editbox.getVisible():
467 return 481 return
468 if keycode == KEY_ENTER: 482 if keycode == KEY_ENTER:
469 self.updateContent() 483 self._updateContent()
470 484
471 def onLostFocus(self, sender): 485 def onLostFocus(self, sender):
472 """Update is done when the focus leaves the raw editbox""" 486 """Update is done when the focus leaves the raw editbox"""
473 if sender != self.editbox or not self.editbox.getVisible(): 487 if sender != self.editbox or not self.editbox.getVisible():
474 return 488 return
475 self.updateContent() 489 self._updateContent()
476 490
477 def updateContent(self, cancel=False): 491 def _updateContent(self, cancel=False):
478 """Send the new content to the backend""" 492 """Send the new content to the backend, remove the entry if it was
493 an empty one (used for creating a new blog post)"""
479 if not self.editbox or not self.editbox.getVisible(): 494 if not self.editbox or not self.editbox.getVisible():
480 return 495 return
481 Window.removeWindowResizeListener(self)
482 self.entry_dialog.setWidth("auto") 496 self.entry_dialog.setWidth("auto")
483 self.entry_dialog.remove(self.edit_panel) 497 self.entry_dialog.remove(self.edit_panel)
484 self.entry_dialog.add(self.bubble) 498 self.entry_dialog.add(self.bubble)
485 new_text = self.editbox.getText().strip() 499 new_text = self.editbox.getText().strip()
486 self.edit_panel = self.editbox = None 500 self.edit_panel = self.editbox = None
501
502 def removeNewEntry():
503 if self.empty:
504 self._blog_panel.removeEntry(self.type, self.id)
505 if self.type == 'main_item':
506 self._blog_panel.setUniBox(enable=False)
507
487 if cancel or new_text == self.editable_content[0] or new_text == "": 508 if cancel or new_text == self.editable_content[0] or new_text == "":
509 removeNewEntry()
488 return 510 return
489 self.editable_content[0] = new_text 511 self.editable_content[0] = new_text
490 extra = {'published': str(self.published)} 512 extra = {'published': str(self.published)}
491 if self.entry.xhtml: 513 if self.empty or self.xhtml:
492 extra.update({'rich': new_text}) 514 extra.update({'rich': new_text})
493 self._blog_panel.host.bridge.call('updateMblog', None, self.pub_data, self.comments, new_text, extra) 515 if self.empty:
494 516 if self.type == 'main_item':
495 def _update(self): 517 self._blog_panel.host.bridge.call('sendMblog', None, None, self._blog_panel.accepted_groups, new_text, extra)
496 """Change the bubble to an editbox""" 518 else:
497 if self.editbox and self.editbox.getVisible(): 519 self._blog_panel.host.bridge.call('sendMblogComment', None, self._parent_entry.comments, new_text, extra)
498 return 520 else:
499 521 self._blog_panel.host.bridge.call('updateMblog', None, self.pub_data, self.comments, new_text, extra)
500 def setOriginalText(text, container): 522 removeNewEntry()
501 text = text.strip() 523
502 container.original_text = text 524 def setEntryDialog(self, edit=False):
503 self.editbox.setWidth('100%') 525 """Set the bubble or the editor
504 self.editbox.setText(text) 526 @param edit: set to True to display the editor"""
505 panel = SimplePanel() 527 if edit:
506 panel.add(container) 528 if self.empty or self.xhtml:
507 panel.setStyleName("bubble") 529 if not self.editbox:
508 panel.addStyleName('bubble-editbox') 530
509 Window.addWindowResizeListener(self) 531 def cb(result):
510 self.onWindowResized() 532 self._updateContent(result == richtext.CANCEL)
533
534 options = ('no_recipient', 'no_sync_unibox', 'no_style', 'update_msg', 'no_close')
535 editor = richtext.RichTextEditor(self._blog_panel.host, self.panel, cb, options=options)
536 editor.setWidth('100%')
537 self.editbox = editor.textarea
538
539 editor.setVisible(True) # needed to build the toolbar
540 if self.editable_content[0]:
541 self._blog_panel.host.bridge.call('syntaxConvert', lambda d: self._setOriginalText(d, editor),
542 self.editable_content[0], self.editable_content[1])
543 else:
544 self._setOriginalText("", editor)
545 else:
546 if not self.editbox:
547 self.editbox = TextArea()
548 self.editbox.addFocusListener(self)
549 self.editbox.addKeyboardListener(self)
550 self._setOriginalText(self.editable_content[0], self.editbox)
551 else:
552 if not self.bubble:
553 self.bubble = HTML()
554 self.bubble.setStyleName("bubble")
555
556 self.bubble.setHTML(addURLToText(html_sanitize(self.content)) if not self.xhtml else self.xhtml)
557 self.entry_dialog.add(self.bubble)
558
559 def _setOriginalText(self, text, container):
560 """Set the original text to be modified in the editor"""
561 text = text.strip()
562 container.original_text = text
563 self.editbox.setWidth('100%')
564 self.editbox.setText(text)
565 panel = SimplePanel()
566 panel.add(container)
567 panel.setStyleName("bubble")
568 panel.addStyleName('bubble-editbox')
569 if self.bubble:
511 self.entry_dialog.remove(self.bubble) 570 self.entry_dialog.remove(self.bubble)
512 self.entry_dialog.add(panel) 571 self.entry_dialog.add(panel)
513 self.editbox.setFocus(True) 572 self.editbox.setFocus(True)
573 if text:
514 self.editbox.setSelectionRange(len(text), 0) 574 self.editbox.setSelectionRange(len(text), 0)
515 self.edit_panel = panel 575 self.edit_panel = panel
516 self.editable_content = [text, container.format if isinstance(container, richtext.RichTextEditor) else None] 576 self.editable_content = [text, container.format if isinstance(container, richtext.RichTextEditor) else None]
517
518 if self.entry.xhtml:
519 options = ('no_recipient', 'no_sync_unibox', 'no_style', 'update_msg', 'no_close')
520
521 def cb(result):
522 self.updateContent(result == richtext.CANCEL)
523
524 editor = richtext.RichTextEditor(self._blog_panel.host, self.panel, cb, options=options)
525 editor.setWidth('100%')
526 editor.setVisible(True) # needed to build the toolbar
527 self.editbox = editor.textarea
528 self._blog_panel.host.bridge.call('syntaxConvert', lambda d: setOriginalText(d, editor),
529 self.editable_content[0], self.editable_content[1])
530 else:
531 self.editbox = TextArea()
532 self.editbox.addFocusListener(self)
533 self.editbox.addKeyboardListener(self)
534 setOriginalText(self.editable_content[0], self.editbox)
535 577
536 def _delete(self): 578 def _delete(self):
537 """Ask confirmation for deletion""" 579 """Ask confirmation for deletion"""
538 def confirm_cb(answer): 580 def confirm_cb(answer):
539 if answer: 581 if answer:
541 583
542 target = 'message and all its comments' if self.comments else 'comment' 584 target = 'message and all its comments' if self.comments else 'comment'
543 _dialog = ConfirmDialog(confirm_cb, text="Do you really want to delete this %s?" % target) 585 _dialog = ConfirmDialog(confirm_cb, text="Do you really want to delete this %s?" % target)
544 _dialog.show() 586 _dialog.show()
545 587
588 def _comment(self):
589 """Add an empty entry for a new comment"""
590 data = {'id': str(time()),
591 'new': True,
592 'type': 'comment',
593 'author': self._blog_panel.host.whoami.bare,
594 'service': self.service,
595 'node': self.node
596 }
597 entry = self._blog_panel.addEntry(data)
598 entry._parent_entry = self
599 entry.setEntryDialog(edit=True)
600
546 601
547 class MicroblogPanel(base_widget.LiberviaWidget): 602 class MicroblogPanel(base_widget.LiberviaWidget):
548 warning_msg_public = "This message will be PUBLIC and everybody will be able to see it, even people you don't know" 603 warning_msg_public = "This message will be PUBLIC and everybody will be able to see it, even people you don't know"
549 warning_msg_group = "This message will be published for all the people of the group <span class='warningTarget'>%s</span>" 604 warning_msg_group = "This message will be published for all the people of the group <span class='warningTarget'>%s</span>"
550 605
552 """Panel used to show microblog 607 """Panel used to show microblog
553 @param accepted_groups: groups displayed in this panel, if empty, show all microblogs from all contacts 608 @param accepted_groups: groups displayed in this panel, if empty, show all microblogs from all contacts
554 """ 609 """
555 base_widget.LiberviaWidget.__init__(self, host, ", ".join(accepted_groups), selectable=True) 610 base_widget.LiberviaWidget.__init__(self, host, ", ".join(accepted_groups), selectable=True)
556 self.setAcceptedGroup(accepted_groups) 611 self.setAcceptedGroup(accepted_groups)
612 self.host = host
557 self.entries = {} 613 self.entries = {}
558 self.comments = {} 614 self.comments = {}
559 self.selected_entry = None 615 self.selected_entry = None
560 self.vpanel = VerticalPanel() 616 self.vpanel = VerticalPanel()
561 self.vpanel.setStyleName('microblogPanel') 617 self.vpanel.setStyleName('microblogPanel')
562 self.setWidget(self.vpanel) 618 self.setWidget(self.vpanel)
619 self.setUniBox(self.host.uni_box)
620
621 def setUniBox(self, enable=False):
622 """Enable or disable the unibox. If it is disabled,
623 display the 'New message' button on top of the panel"""
624 if enable:
625 return
626 if hasattr(self, 'new_button'):
627 self.new_button.setVisible(True)
628 else:
629 def addBox():
630 self.new_button.setVisible(False)
631 data = {'id': str(time()),
632 'new': True,
633 'author': self.host.whoami.bare,
634 }
635 entry = self.addEntry(data)
636 entry.setEntryDialog(edit=True)
637 self.new_button = Button("New message", listener=addBox)
638 self.new_button.setStyleName("microblogNewButton")
639 self.vpanel.insert(self.new_button, 0)
563 640
564 @classmethod 641 @classmethod
565 def registerClass(cls): 642 def registerClass(cls):
566 base_widget.LiberviaWidget.addDropKey("GROUP", cls.createPanel) 643 base_widget.LiberviaWidget.addDropKey("GROUP", cls.createPanel)
567 base_widget.LiberviaWidget.addDropKey("CONTACT_TITLE", cls.createMetaPanel) 644 base_widget.LiberviaWidget.addDropKey("CONTACT_TITLE", cls.createMetaPanel)
649 print "adding blogs for [%s]" % publisher 726 print "adding blogs for [%s]" % publisher
650 for mblog in mblogs[publisher]: 727 for mblog in mblogs[publisher]:
651 if not "content" in mblog: 728 if not "content" in mblog:
652 print ("WARNING: No content found in microblog [%s]", mblog) 729 print ("WARNING: No content found in microblog [%s]", mblog)
653 continue 730 continue
654 mblog_item = MicroblogItem(mblog) 731 self.addEntry(mblog)
655 self.addEntry(mblog_item)
656 732
657 def mblogsInsert(self, mblogs): 733 def mblogsInsert(self, mblogs):
658 """ Insert several microblogs at once 734 """ Insert several microblogs at once
659 @param mblogs: list of microblogs 735 @param mblogs: list of microblogs
660 """ 736 """
661 for mblog in mblogs: 737 for mblog in mblogs:
662 if not "content" in mblog: 738 if not "content" in mblog:
663 print ("WARNING: No content found in microblog [%s]", mblog) 739 print ("WARNING: No content found in microblog [%s]", mblog)
664 continue 740 continue
665 mblog_item = MicroblogItem(mblog) 741 self.addEntry(mblog)
666 self.addEntry(mblog_item)
667 742
668 def _chronoInsert(self, vpanel, entry, reverse=True): 743 def _chronoInsert(self, vpanel, entry, reverse=True):
669 """ Insert an entry in chronological order 744 """ Insert an entry in chronological order
670 @param vpanel: VerticalPanel instance 745 @param vpanel: VerticalPanel instance
671 @param entry: MicroblogEntry 746 @param entry: MicroblogEntry
672 @param reverse: more recent entry on top if True, chronological order else""" 747 @param reverse: more recent entry on top if True, chronological order else"""
748 if entry.empty:
749 entry.published = time()
673 # we look for the right index to insert our entry: 750 # we look for the right index to insert our entry:
674 # if reversed, we insert the entry above the first entry 751 # if reversed, we insert the entry above the first entry
675 # in the past 752 # in the past
676 idx = 0 753 idx = 0
677 754
687 break 764 break
688 idx += 1 765 idx += 1
689 766
690 vpanel.insert(entry, idx) 767 vpanel.insert(entry, idx)
691 768
692 def addEntry(self, mblog_item): 769 def addEntry(self, data):
693 """Add an entry to the panel 770 """Add an entry to the panel
694 @param mblog_item: MicroblogItem instance 771 @param data: dict containing the item data
695 """ 772 @return: the added entry, or None
696 if mblog_item.type == "comment": 773 """
697 if not mblog_item.hash in self.comments: 774 _entry = MicroblogEntry(self, data)
775 if _entry.type == "comment":
776 if not _entry.hash in self.comments:
698 # The comments node is not known in this panel 777 # The comments node is not known in this panel
699 return 778 return None
700 _entry = MicroblogEntry(self, mblog_item) 779 parent = self.comments[_entry.hash]
701 parent = self.comments[mblog_item.hash]
702 parent_idx = self.vpanel.getWidgetIndex(parent) 780 parent_idx = self.vpanel.getWidgetIndex(parent)
703 # we find or create the panel where the comment must be inserted 781 # we find or create the panel where the comment must be inserted
704 try: 782 try:
705 sub_panel = self.vpanel.getWidget(parent_idx + 1) 783 sub_panel = self.vpanel.getWidget(parent_idx + 1)
706 except IndexError: 784 except IndexError:
710 sub_panel.setStyleName('microblogPanel') 788 sub_panel.setStyleName('microblogPanel')
711 sub_panel.addStyleName('subPanel') 789 sub_panel.addStyleName('subPanel')
712 self.vpanel.insert(sub_panel, parent_idx + 1) 790 self.vpanel.insert(sub_panel, parent_idx + 1)
713 for idx in xrange(0, len(sub_panel.getChildren())): 791 for idx in xrange(0, len(sub_panel.getChildren())):
714 comment = sub_panel.getIndexedChild(idx) 792 comment = sub_panel.getIndexedChild(idx)
715 if comment.pub_data[2] == mblog_item.id: 793 if comment.pub_data[2] == _entry.id:
716 # update an existing comment 794 # update an existing comment
717 sub_panel.remove(comment) 795 sub_panel.remove(comment)
718 sub_panel.insert(_entry, idx) 796 sub_panel.insert(_entry, idx)
719 return 797 return _entry
720 # we want comments to be inserted in chronological order 798 # we want comments to be inserted in chronological order
721 self._chronoInsert(sub_panel, _entry, reverse=False) 799 self._chronoInsert(sub_panel, _entry, reverse=False)
722 return 800 return _entry
723 801
724 update = mblog_item.id in self.entries 802 if _entry.id in self.entries: # update
725 _entry = MicroblogEntry(self, mblog_item) 803 idx = self.vpanel.getWidgetIndex(self.entries[_entry.id])
726 if update: 804 self.vpanel.remove(self.entries[_entry.id])
727 idx = self.vpanel.getWidgetIndex(self.entries[mblog_item.id])
728 self.vpanel.remove(self.entries[mblog_item.id])
729 self.vpanel.insert(_entry, idx) 805 self.vpanel.insert(_entry, idx)
730 else: 806 else: # new entry
731 self._chronoInsert(self.vpanel, _entry) 807 self._chronoInsert(self.vpanel, _entry)
732 self.entries[mblog_item.id] = _entry 808 self.entries[_entry.id] = _entry
733 809
734 if mblog_item.comments: 810 if _entry.comments:
735 # entry has comments, we keep the comment node as a reference 811 # entry has comments, we keep the comment node as a reference
736 self.comments[mblog_item.comments_hash] = _entry 812 self.comments[_entry.hash] = _entry
737 self.host.bridge.call('getMblogComments', self.mblogsInsert, mblog_item.comments_service, mblog_item.comments_node) 813 self.host.bridge.call('getMblogComments', self.mblogsInsert, _entry.service, _entry.node)
814
815 return _entry
738 816
739 def removeEntry(self, type_, id_): 817 def removeEntry(self, type_, id_):
740 """Remove an entry from the panel 818 """Remove an entry from the panel
741 @param type_: entry type ('main_item' or 'comment') 819 @param type_: entry type ('main_item' or 'comment')
742 @param id_: entry id 820 @param id_: entry id
743 """ 821 """
744 for child in self.vpanel.getChildren(): 822 for child in self.vpanel.getChildren():
745 if isinstance(child, MicroblogEntry) and type_ == 'main_item': 823 if isinstance(child, MicroblogEntry) and type_ == 'main_item':
746 print child.pub_data
747 if child.pub_data[2] == id_: 824 if child.pub_data[2] == id_:
748 main_idx = self.vpanel.getWidgetIndex(child) 825 main_idx = self.vpanel.getWidgetIndex(child)
749 try: 826 try:
750 sub_panel = self.vpanel.getWidget(main_idx + 1) 827 sub_panel = self.vpanel.getWidget(main_idx + 1)
751 if isinstance(sub_panel, VerticalPanel): 828 if isinstance(sub_panel, VerticalPanel):