changeset 256:0e7f3944bd27

browser_side: added contact group manager based on ListManager
author souliane <souliane@mailoo.org>
date Sat, 09 Nov 2013 09:39:45 +0100
parents da0487f0a2e7
children 377de26d5bc2
files browser_side/contact_group.py browser_side/list_manager.py browser_side/menu.py public/libervia.css
diffstat 4 files changed, 263 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/browser_side/contact_group.py	Sat Nov 09 09:39:45 2013 +0100
@@ -0,0 +1,209 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+"""
+Libervia: a Salut à Toi frontend
+Copyright (C) 2013 Adrien Cossa <souliane@mailoo.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+
+from pyjamas.ui.FlexTable import FlexTable
+from browser_side.dialog import ConfirmDialog
+from list_manager import ListManager
+import contact
+from pyjamas.Timer import Timer
+from pyjamas.ui.Button import Button
+from pyjamas.ui.HorizontalPanel import HorizontalPanel
+from pyjamas.ui.VerticalPanel import VerticalPanel
+from pyjamas.ui.DialogBox import DialogBox
+import dialog
+
+
+class ContactGroupManager(ListManager):
+    """A manager for sub-panels to assign contacts to each group."""
+
+    def __init__(self, parent, keys_dict, contact_list, offsets, style):
+        ListManager.__init__(self, parent, keys_dict, contact_list, offsets, style)
+        self.registerPopupMenuPanel(entries={"Remove group": {}},
+                                    callback=lambda sender, key: Timer(5, lambda: self.removeContactKey(sender, key)))
+
+    def removeContactKey(self, sender, key):
+        key = sender.getText()
+
+        def confirm_cb(answer):
+            if answer:
+                (y, x) = self._parent.getIndex(self.__children[key]["button"])
+                self._parent.removeCell(y, x + 1)
+                self._parent.removeCell(y, x)
+                del self.__keys_dict[key]
+                del self.__children[key]
+                self._parent.add_group_panel.groups.remove(key)
+
+        _dialog = ConfirmDialog(confirm_cb, text="Do you really want to delete the group '%s'?" % key)
+        _dialog.show()
+
+    def removeFromRemainingList(self, contact_):
+        ListManager.removeFromRemainingList(self, contact_)
+        self._parent.updateContactList(contact_=contact_)
+
+    def addToRemainingList(self, contact_):
+        ListManager.addToRemainingList(self, contact_)
+        self._parent.updateContactList(contact_=contact_)
+
+
+class ContactGroupEditor(FlexTable):
+    """Panel for the contact groups manager."""
+
+    def __init__(self, host, parent=None, onCloseCallback=None):
+        # This must be done before FlexTable.__init__ because it is used by setVisible
+        self.host = host
+        if parent is None:
+            parent = DialogBox(autoHide=False, centered=True)
+            parent.setHTML("Manage contact groups")
+
+        self._parent = parent
+        self._on_close_callback = onCloseCallback
+
+        groups_list = self.host.contact_panel.groups.keys()
+        groups_list.sort()
+        FlexTable.__init__(self, len(groups_list) + 2, 3)
+        self.addStyleName('contactGroupEditor')
+
+        def cb(text):
+            nb_keys = len(self.groups.keys)
+            self.getFlexCellFormatter().setColSpan(nb_keys + 1, 0, 1)
+            self.getFlexCellFormatter().setColSpan(nb_keys + 2, 0, 1)
+            self.remove(self.add_group_panel)
+            self.remove(self.command)
+            self.groups.addContactKey(text)
+            refresh()
+
+        # overwrite the default style which has been set for rich text editor
+        style = {
+           "keyItem": "group",
+           "popupMenuItem": "popupMenuItem",
+           "removeButton": "contactGroupRemoveButton",
+           "buttonCell": "contactGroupButtonCell",
+           "keyPanel": "contactGroupPanel"
+        }
+        self.all_contacts = self.host.contact_panel.getContacts()
+        self.groups = ContactGroupManager(self, groups_list, self.all_contacts, style=style)
+        self.groups.createWidgets()
+
+        self.add_group_panel = dialog.AddGroupPanel(groups_list, cb)
+        self.add_group_panel.addStyleName("addContactGroupPanel")
+
+        self.command = HorizontalPanel()
+        self.command.addStyleName("marginAuto")
+        self.command.add(Button("Cancel", listener=self.cancelWithoutSaving))
+        self.command.add(Button("Save", listener=self.closeAndSave))
+
+        contact_panel = VerticalPanel()
+
+        # checkbox has been replaced by a button
+        self.checkbox = Button("", self.toggleContacts)
+        self.checkbox.getChecked = lambda: self.checkbox.checked if hasattr(self.checkbox, "checked") else None
+        self.checkbox.addStyleName("toggleAssignedContacts")
+        contact_panel.add(self.checkbox)
+        self.contacts = contact.GenericContactList(host)
+        contact_panel.add(self.contacts)
+        for contact in self.all_contacts:
+            self.contacts.add(contact)
+        self.setWidget(0, 2, contact_panel)
+
+        def refresh():
+            nb_keys = len(self.groups.keys)
+            self.getFlexCellFormatter().setColSpan(nb_keys + 1, 0, 2)  # add group panel
+            self.setWidget(nb_keys + 1, 0, self.add_group_panel)
+            self.getFlexCellFormatter().setColSpan(nb_keys + 2, 0, 3)  # buttons panel
+            self.setWidget(nb_keys + 2, 0, self.command)
+            self.getFlexCellFormatter().setRowSpan(0, 2, nb_keys + 2)  # contact list
+
+        self.groups.setContacts(self.host.contact_panel.groups)
+        refresh()
+        self.restore_contact_panel = False
+        if self.host.contact_panel.getVisible():
+            self.restore_contact_panel = True
+            self.host.panel._contactsSwitch()
+        self.toggleContacts()
+        parent.add(self)
+        parent.setVisible(True)
+        if isinstance(parent, DialogBox):
+            parent.center()
+
+    def toggleContacts(self, sender=None):
+        if sender is None:
+            sender = self.checkbox
+        if sender.getChecked():
+            sender.checked = False
+            sender.setText("Hide assigned")
+        else:
+            sender.checked = True
+            sender.setText("Show assigned")
+        self.updateContactList(sender)
+
+    def updateContactList(self, sender=None, contact_=None):
+        sender = self.checkbox
+        if sender.getChecked() is None:
+            # do not update during initialization
+            return
+        if contact_ is not None:
+            if contact_ not in self.all_contacts or not sender.getChecked():
+                return
+            all_contacts = [contact_]
+        else:
+            all_contacts = self.all_contacts
+        for contact_ in all_contacts:
+            if sender.getChecked():
+                if contact_ in self.groups.remaining_list:
+                    self.contacts.getContactLabel(contact_).setVisible(True)
+                else:
+                    self.contacts.getContactLabel(contact_).setVisible(False)
+            else:
+                self.contacts.getContactLabel(contact_).setVisible(True)
+
+    def __close(self):
+        """Remove the widget from parent or close the popup."""
+        if isinstance(self._parent, DialogBox):
+            self._parent.hide()
+        self._parent.remove(self)
+        if self._on_close_callback is not None:
+            self._on_close_callback()
+        if self.restore_contact_panel:
+            self.host.panel._contactsSwitch()
+
+    def cancelWithoutSaving(self):
+        """Ask for confirmation before closing the dialog."""
+        def confirm_cb(answer):
+            if answer:
+                self.__close()
+
+        _dialog = ConfirmDialog(confirm_cb, text="Do you really want to cancel without saving?")
+        _dialog.show()
+
+    def closeAndSave(self):
+        map_ = {}
+        for contact_ in self.all_contacts:
+            map_[contact_] = set()
+        contacts = self.groups.getContacts()
+        for group in contacts.keys():
+            for contact_ in contacts[group]:
+                map_[contact_].add(group)
+        for contact_ in map_.keys():
+            groups = map_[contact_]
+            current_groups = self.host.contact_panel.getContactGroups(contact_)
+            if groups != current_groups:
+                self.host.bridge.call('updateContact', None, contact_, '', list(groups))
+        self.__close()
--- a/browser_side/list_manager.py	Sat Nov 09 15:31:39 2013 +0100
+++ b/browser_side/list_manager.py	Sat Nov 09 09:39:45 2013 +0100
@@ -86,6 +86,7 @@
 
         self.style = {
            "keyItem": "recipientTypeItem",
+           "popupMenuItem": "recipientTypeItem",
            "buttonCell": "recipientButtonCell",
            "dragoverPanel": "dragover-recipientPanel",
            "keyPanel": "recipientPanel",
@@ -110,7 +111,7 @@
     def _addChild(self, entry, title_format):
         """Add a button and FlowPanel for the corresponding map entry."""
         button = Button(title_format % entry["title"])
-        button.addStyleName(self.style["keyItem"])
+        button.setStyleName(self.style["keyItem"])
         if hasattr(entry, "desc"):
             button.setTitle(entry["desc"])
         if not "optional" in entry:
@@ -211,7 +212,7 @@
 
     def registerPopupMenuPanel(self, entries, hide, callback):
         "Register a popup menu panel that will be bound to all contact keys elements."
-        self.popup_menu = panels.PopupMenuPanel(entries=entries, hide=hide, callback=callback, item_style="recipientTypeItem")
+        self.popup_menu = panels.PopupMenuPanel(entries=entries, hide=hide, callback=callback, item_style=self.style["popupMenuItem"])
 
 
 class DragAutoCompleteTextBox(AutoCompleteTextBox, DragWidget, MouseHandler):
@@ -427,6 +428,9 @@
     def setContacts(self, tab):
         """Set the contacts."""
         self.emptyContacts()
+        if isinstance(tab, set):
+            tab = list(tab)
+        tab.sort()
         for contact in tab:
             self.addContact(contact, resetLastTextBox=False)
         self.__resetLastTextBox()
--- a/browser_side/menu.py	Sat Nov 09 15:31:39 2013 +0100
+++ b/browser_side/menu.py	Sat Nov 09 09:39:45 2013 +0100
@@ -40,6 +40,7 @@
 from xmlui import XMLUI
 import panels
 import dialog
+from contact_group import ContactGroupEditor
 import re
 
 
@@ -138,12 +139,13 @@
         menu_general.addItem("Disconnect", MenuCmd(self, "onDisconnect"))
 
         menu_contacts = MenuBar(vertical=True)
-        menu_contacts.addItem("add contact", MenuCmd(self, "onAddContact"))
-        menu_contacts.addItem("update contact", MenuCmd(self, "onUpdateContact"))
-        menu_contacts.addItem("remove contact", MenuCmd(self, "onRemoveContact"))
+        menu_contacts.addItem("Add contact", MenuCmd(self, "onAddContact"))
+        menu_contacts.addItem("Update contact", MenuCmd(self, "onUpdateContact"))
+        menu_contacts.addItem("Remove contact", MenuCmd(self, "onRemoveContact"))
+        menu_contacts.addItem("Manage groups", MenuCmd(self, "onManageContactGroups"))
 
         menu_group = MenuBar(vertical=True)
-        menu_group.addItem("join room", MenuCmd(self, "onJoinRoom"))
+        menu_group.addItem("Join room", MenuCmd(self, "onJoinRoom"))
         menu_group.addItem("Collective radio", MenuCmd(self, "onCollectiveRadio"))
 
         menu_games = MenuBar(vertical=True)
@@ -278,6 +280,14 @@
         _dialog = dialog.GenericConfirmDialog([_contacts_list], dialogCb, "Who do you want to remove from your contacts ?")
         _dialog.show()
 
+    def onManageContactGroups(self):
+        """Open the contact groups manager."""
+
+        def onCloseCallback():
+            pass
+
+        ContactGroupEditor(self.host, None, onCloseCallback)
+
     #Group menu
     def onJoinRoom(self):
         _dialog = None
--- a/public/libervia.css	Sat Nov 09 15:31:39 2013 +0100
+++ b/public/libervia.css	Sat Nov 09 09:39:45 2013 +0100
@@ -1257,3 +1257,37 @@
     cursor: pointer;
     border-radius: 5px;
 }
+
+/* Contact group manager */
+
+.contactGroupEditor {
+	width: 800px;
+	max-width:800px;
+	min-width: 800px;
+	margin-top: 9px;
+	margin-left:18px;
+}
+
+.contactGroupRemoveButton {
+	margin: 0px 10px 0px 0px;
+	padding: 0px;
+	border: 1px dashed red;
+    border-radius: 5px 5px 5px 5px;
+}
+
+.addContactGroupPanel {
+	
+}
+
+.contactGroupPanel {
+	vertical-align:middle;
+}
+
+.toggleAssignedContacts {
+    white-space: nowrap;
+}
+
+.contactGroupButtonCell {
+	vertical-align: baseline;
+	width: 55px;
+}
\ No newline at end of file