diff browser_side/contact_group.py @ 263:d3c734669577

browser_side: improvements for lists and contact groups manager: - use DockPanel to deal with UI problems - fixed issues with the autocomplete list - avoid duplicate contacts in a contact list - signal invalid contacts with a red border - check for invalid contacts in the form before saving - better genericity for the class DragAutoCompleteTextBox
author souliane <souliane@mailoo.org>
date Mon, 11 Nov 2013 12:48:33 +0100
parents 0e7f3944bd27
children 2067d6241927
line wrap: on
line diff
--- a/browser_side/contact_group.py	Mon Nov 11 10:44:44 2013 +0100
+++ b/browser_side/contact_group.py	Mon Nov 11 12:48:33 2013 +0100
@@ -20,15 +20,17 @@
 """
 
 from pyjamas.ui.FlexTable import FlexTable
-from browser_side.dialog import ConfirmDialog
-from list_manager import ListManager
-import contact
+from pyjamas.ui.DockPanel import DockPanel
 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
+from pyjamas.ui import HasAlignment
+from browser_side.dialog import ConfirmDialog, InfoDialog
+from list_manager import ListManager
 import dialog
+import contact
 
 
 class ContactGroupManager(ListManager):
@@ -44,52 +46,77 @@
 
         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)
+                ListManager.removeContactKey(self, key)
+                self._parent.removeKeyFromAddGroupPanel(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 removeFromRemainingList(self, contacts):
+        ListManager.removeFromRemainingList(self, contacts)
+        self._parent.updateContactList(contacts=contacts)
 
-    def addToRemainingList(self, contact_):
-        ListManager.addToRemainingList(self, contact_)
-        self._parent.updateContactList(contact_=contact_)
+    def addToRemainingList(self, contacts, ignore_key=None):
+        ListManager.addToRemainingList(self, contacts, ignore_key)
+        self._parent.updateContactList(contacts=contacts)
 
 
-class ContactGroupEditor(FlexTable):
+class ContactGroupEditor(DockPanel):
     """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
+        DockPanel.__init__(self)
         self.host = host
+
+        # eventually display in a popup
         if parent is None:
             parent = DialogBox(autoHide=False, centered=True)
             parent.setHTML("Manage contact groups")
-
         self._parent = parent
         self._on_close_callback = onCloseCallback
+        self.all_contacts = self.host.contact_panel.getContacts()
 
         groups_list = self.host.contact_panel.groups.keys()
         groups_list.sort()
-        FlexTable.__init__(self, len(groups_list) + 2, 3)
-        self.addStyleName('contactGroupEditor')
+
+        self.add_group_panel = self.getAddGroupPanel(groups_list)
+        south_panel = self.getCloseSaveButtons()
+        center_panel = self.getContactGroupManager(groups_list)
+        east_panel = self.getContactList()
+
+        self.add(self.add_group_panel, DockPanel.CENTER)
+        self.add(east_panel, DockPanel.EAST)
+        self.add(center_panel, DockPanel.NORTH)
+        self.add(south_panel, DockPanel.SOUTH)
+
+        self.setCellHorizontalAlignment(center_panel, HasAlignment.ALIGN_LEFT)
+        self.setCellVerticalAlignment(center_panel, HasAlignment.ALIGN_TOP)
+        self.setCellHorizontalAlignment(east_panel, HasAlignment.ALIGN_RIGHT)
+        self.setCellVerticalAlignment(east_panel, HasAlignment.ALIGN_TOP)
+        self.setCellVerticalAlignment(self.add_group_panel, HasAlignment.ALIGN_BOTTOM)
+        self.setCellHorizontalAlignment(self.add_group_panel, HasAlignment.ALIGN_LEFT)
+        self.setCellVerticalAlignment(south_panel, HasAlignment.ALIGN_BOTTOM)
+        self.setCellHorizontalAlignment(south_panel, HasAlignment.ALIGN_CENTER)
 
-        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()
+        # need to be done after the contact list has been initialized
+        self.groups.setContacts(self.host.contact_panel.groups)
+        self.toggleContacts(showAll=True)
+
+        # Hide the contacts list from the main panel to not confuse the user
+        self.restore_contact_panel = False
+        if self.host.contact_panel.getVisible():
+            self.restore_contact_panel = True
+            self.host.panel._contactsSwitch()
 
+        parent.add(self)
+        parent.setVisible(True)
+        if isinstance(parent, DialogBox):
+            parent.center()
+
+    def getContactGroupManager(self, groups_list):
+        """Set the list manager for the groups"""
+        flex_table = FlexTable(len(groups_list), 2)
+        flex_table.addStyleName('contactGroupEditor')
         # overwrite the default style which has been set for rich text editor
         style = {
            "keyItem": "group",
@@ -98,81 +125,76 @@
            "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))
+        self.groups = ContactGroupManager(flex_table, groups_list, self.all_contacts, style=style)
+        self.groups.createWidgets()  # widgets are automatically added to FlexTable
+        # FIXME: clean that part which is dangerous
+        flex_table.updateContactList = self.updateContactList
+        flex_table.removeKeyFromAddGroupPanel = self.add_group_panel.groups.remove
+        return flex_table
 
-        contact_panel = VerticalPanel()
+    def getAddGroupPanel(self, groups_list):
+        """Add the 'Add group' panel to the FlexTable"""
 
-        # 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 add_group_cb(text):
+            self.groups.addContactKey(text)
+            self.add_group_panel.textbox.setFocus(True)
+
+        add_group_panel = dialog.AddGroupPanel(groups_list, add_group_cb)
+        add_group_panel.addStyleName("addContactGroupPanel")
+        return add_group_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
+    def getCloseSaveButtons(self):
+        """Add the buttons to close the dialog / save the groups"""
+        buttons = HorizontalPanel()
+        buttons.addStyleName("marginAuto")
+        buttons.add(Button("Cancel", listener=self.cancelWithoutSaving))
+        buttons.add(Button("Save", listener=self.closeAndSave))
+        return buttons
 
-        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 getContactList(self):
+        """Add the contact list to the DockPanel"""
+        self.toggle = Button("", self.toggleContacts)
+        self.toggle.addStyleName("toggleAssignedContacts")
+        self.contacts = contact.GenericContactList(self.host)
+        for contact_ in self.all_contacts:
+            self.contacts.add(contact_)
+        contact_panel = VerticalPanel()
+        contact_panel.add(self.toggle)
+        contact_panel.add(self.contacts)
+        return contact_panel
 
-    def toggleContacts(self, sender=None):
+    def toggleContacts(self, sender=None, showAll=None):
+        """Callback for the toggle button"""
         if sender is None:
-            sender = self.checkbox
-        if sender.getChecked():
-            sender.checked = False
+            sender = self.toggle
+        sender.showAll = showAll if showAll is not None else not sender.showAll
+        if sender.showAll:
             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
+    def updateContactList(self, sender=None, contacts=None):
+        """Update the contact list regarding the toggle button"""
+        if not hasattr(self, "toggle") or not hasattr(self.toggle, "showAll"):
             return
-        if contact_ is not None:
-            if contact_ not in self.all_contacts or not sender.getChecked():
-                return
-            all_contacts = [contact_]
+        sender = self.toggle
+        if contacts is not None:
+            if not isinstance(contacts, list):
+                contacts = [contacts]
+            for contact_ in contacts:
+                if contact_ not in self.all_contacts:
+                    contacts.remove(contact_)
         else:
-            all_contacts = self.all_contacts
-        for contact_ in all_contacts:
-            if sender.getChecked():
+            contacts = self.all_contacts
+        for contact_ in contacts:
+            if sender.showAll:
+                self.contacts.getContactLabel(contact_).setVisible(True)
+            else:
                 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."""
@@ -194,13 +216,20 @@
         _dialog.show()
 
     def closeAndSave(self):
+        """Call bridge methods to save the changes and close the dialog"""
         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)
+                try:
+                    map_[contact_].add(group)
+                except KeyError:
+                    InfoDialog("Invalid contact",
+                           "The contact '%s' is not your contact list but it has been assigned to the group '%s'." % (contact_, group) +
+                           "Your changes could not be saved: please check your assignments and save again.", Width="400px").center()
+                    return
         for contact_ in map_.keys():
             groups = map_[contact_]
             current_groups = self.host.contact_panel.getContactGroups(contact_)