Mercurial > libervia-web
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): |