comparison 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
comparison
equal deleted inserted replaced
262:30c01671e338 263:d3c734669577
18 You should have received a copy of the GNU Affero General Public License 18 You should have received a copy of the GNU Affero General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. 19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 """ 20 """
21 21
22 from pyjamas.ui.FlexTable import FlexTable 22 from pyjamas.ui.FlexTable import FlexTable
23 from browser_side.dialog import ConfirmDialog 23 from pyjamas.ui.DockPanel import DockPanel
24 from list_manager import ListManager
25 import contact
26 from pyjamas.Timer import Timer 24 from pyjamas.Timer import Timer
27 from pyjamas.ui.Button import Button 25 from pyjamas.ui.Button import Button
28 from pyjamas.ui.HorizontalPanel import HorizontalPanel 26 from pyjamas.ui.HorizontalPanel import HorizontalPanel
29 from pyjamas.ui.VerticalPanel import VerticalPanel 27 from pyjamas.ui.VerticalPanel import VerticalPanel
30 from pyjamas.ui.DialogBox import DialogBox 28 from pyjamas.ui.DialogBox import DialogBox
29 from pyjamas.ui import HasAlignment
30 from browser_side.dialog import ConfirmDialog, InfoDialog
31 from list_manager import ListManager
31 import dialog 32 import dialog
33 import contact
32 34
33 35
34 class ContactGroupManager(ListManager): 36 class ContactGroupManager(ListManager):
35 """A manager for sub-panels to assign contacts to each group.""" 37 """A manager for sub-panels to assign contacts to each group."""
36 38
42 def removeContactKey(self, sender, key): 44 def removeContactKey(self, sender, key):
43 key = sender.getText() 45 key = sender.getText()
44 46
45 def confirm_cb(answer): 47 def confirm_cb(answer):
46 if answer: 48 if answer:
47 (y, x) = self._parent.getIndex(self.__children[key]["button"]) 49 ListManager.removeContactKey(self, key)
48 self._parent.removeCell(y, x + 1) 50 self._parent.removeKeyFromAddGroupPanel(key)
49 self._parent.removeCell(y, x)
50 del self.__keys_dict[key]
51 del self.__children[key]
52 self._parent.add_group_panel.groups.remove(key)
53 51
54 _dialog = ConfirmDialog(confirm_cb, text="Do you really want to delete the group '%s'?" % key) 52 _dialog = ConfirmDialog(confirm_cb, text="Do you really want to delete the group '%s'?" % key)
55 _dialog.show() 53 _dialog.show()
56 54
57 def removeFromRemainingList(self, contact_): 55 def removeFromRemainingList(self, contacts):
58 ListManager.removeFromRemainingList(self, contact_) 56 ListManager.removeFromRemainingList(self, contacts)
59 self._parent.updateContactList(contact_=contact_) 57 self._parent.updateContactList(contacts=contacts)
60 58
61 def addToRemainingList(self, contact_): 59 def addToRemainingList(self, contacts, ignore_key=None):
62 ListManager.addToRemainingList(self, contact_) 60 ListManager.addToRemainingList(self, contacts, ignore_key)
63 self._parent.updateContactList(contact_=contact_) 61 self._parent.updateContactList(contacts=contacts)
64 62
65 63
66 class ContactGroupEditor(FlexTable): 64 class ContactGroupEditor(DockPanel):
67 """Panel for the contact groups manager.""" 65 """Panel for the contact groups manager."""
68 66
69 def __init__(self, host, parent=None, onCloseCallback=None): 67 def __init__(self, host, parent=None, onCloseCallback=None):
70 # This must be done before FlexTable.__init__ because it is used by setVisible 68 DockPanel.__init__(self)
71 self.host = host 69 self.host = host
70
71 # eventually display in a popup
72 if parent is None: 72 if parent is None:
73 parent = DialogBox(autoHide=False, centered=True) 73 parent = DialogBox(autoHide=False, centered=True)
74 parent.setHTML("Manage contact groups") 74 parent.setHTML("Manage contact groups")
75
76 self._parent = parent 75 self._parent = parent
77 self._on_close_callback = onCloseCallback 76 self._on_close_callback = onCloseCallback
77 self.all_contacts = self.host.contact_panel.getContacts()
78 78
79 groups_list = self.host.contact_panel.groups.keys() 79 groups_list = self.host.contact_panel.groups.keys()
80 groups_list.sort() 80 groups_list.sort()
81 FlexTable.__init__(self, len(groups_list) + 2, 3) 81
82 self.addStyleName('contactGroupEditor') 82 self.add_group_panel = self.getAddGroupPanel(groups_list)
83 83 south_panel = self.getCloseSaveButtons()
84 def cb(text): 84 center_panel = self.getContactGroupManager(groups_list)
85 nb_keys = len(self.groups.keys) 85 east_panel = self.getContactList()
86 self.getFlexCellFormatter().setColSpan(nb_keys + 1, 0, 1) 86
87 self.getFlexCellFormatter().setColSpan(nb_keys + 2, 0, 1) 87 self.add(self.add_group_panel, DockPanel.CENTER)
88 self.remove(self.add_group_panel) 88 self.add(east_panel, DockPanel.EAST)
89 self.remove(self.command) 89 self.add(center_panel, DockPanel.NORTH)
90 self.groups.addContactKey(text) 90 self.add(south_panel, DockPanel.SOUTH)
91 refresh() 91
92 92 self.setCellHorizontalAlignment(center_panel, HasAlignment.ALIGN_LEFT)
93 self.setCellVerticalAlignment(center_panel, HasAlignment.ALIGN_TOP)
94 self.setCellHorizontalAlignment(east_panel, HasAlignment.ALIGN_RIGHT)
95 self.setCellVerticalAlignment(east_panel, HasAlignment.ALIGN_TOP)
96 self.setCellVerticalAlignment(self.add_group_panel, HasAlignment.ALIGN_BOTTOM)
97 self.setCellHorizontalAlignment(self.add_group_panel, HasAlignment.ALIGN_LEFT)
98 self.setCellVerticalAlignment(south_panel, HasAlignment.ALIGN_BOTTOM)
99 self.setCellHorizontalAlignment(south_panel, HasAlignment.ALIGN_CENTER)
100
101 # need to be done after the contact list has been initialized
102 self.groups.setContacts(self.host.contact_panel.groups)
103 self.toggleContacts(showAll=True)
104
105 # Hide the contacts list from the main panel to not confuse the user
106 self.restore_contact_panel = False
107 if self.host.contact_panel.getVisible():
108 self.restore_contact_panel = True
109 self.host.panel._contactsSwitch()
110
111 parent.add(self)
112 parent.setVisible(True)
113 if isinstance(parent, DialogBox):
114 parent.center()
115
116 def getContactGroupManager(self, groups_list):
117 """Set the list manager for the groups"""
118 flex_table = FlexTable(len(groups_list), 2)
119 flex_table.addStyleName('contactGroupEditor')
93 # overwrite the default style which has been set for rich text editor 120 # overwrite the default style which has been set for rich text editor
94 style = { 121 style = {
95 "keyItem": "group", 122 "keyItem": "group",
96 "popupMenuItem": "popupMenuItem", 123 "popupMenuItem": "popupMenuItem",
97 "removeButton": "contactGroupRemoveButton", 124 "removeButton": "contactGroupRemoveButton",
98 "buttonCell": "contactGroupButtonCell", 125 "buttonCell": "contactGroupButtonCell",
99 "keyPanel": "contactGroupPanel" 126 "keyPanel": "contactGroupPanel"
100 } 127 }
101 self.all_contacts = self.host.contact_panel.getContacts() 128 self.groups = ContactGroupManager(flex_table, groups_list, self.all_contacts, style=style)
102 self.groups = ContactGroupManager(self, groups_list, self.all_contacts, style=style) 129 self.groups.createWidgets() # widgets are automatically added to FlexTable
103 self.groups.createWidgets() 130 # FIXME: clean that part which is dangerous
104 131 flex_table.updateContactList = self.updateContactList
105 self.add_group_panel = dialog.AddGroupPanel(groups_list, cb) 132 flex_table.removeKeyFromAddGroupPanel = self.add_group_panel.groups.remove
106 self.add_group_panel.addStyleName("addContactGroupPanel") 133 return flex_table
107 134
108 self.command = HorizontalPanel() 135 def getAddGroupPanel(self, groups_list):
109 self.command.addStyleName("marginAuto") 136 """Add the 'Add group' panel to the FlexTable"""
110 self.command.add(Button("Cancel", listener=self.cancelWithoutSaving)) 137
111 self.command.add(Button("Save", listener=self.closeAndSave)) 138 def add_group_cb(text):
112 139 self.groups.addContactKey(text)
140 self.add_group_panel.textbox.setFocus(True)
141
142 add_group_panel = dialog.AddGroupPanel(groups_list, add_group_cb)
143 add_group_panel.addStyleName("addContactGroupPanel")
144 return add_group_panel
145
146 def getCloseSaveButtons(self):
147 """Add the buttons to close the dialog / save the groups"""
148 buttons = HorizontalPanel()
149 buttons.addStyleName("marginAuto")
150 buttons.add(Button("Cancel", listener=self.cancelWithoutSaving))
151 buttons.add(Button("Save", listener=self.closeAndSave))
152 return buttons
153
154 def getContactList(self):
155 """Add the contact list to the DockPanel"""
156 self.toggle = Button("", self.toggleContacts)
157 self.toggle.addStyleName("toggleAssignedContacts")
158 self.contacts = contact.GenericContactList(self.host)
159 for contact_ in self.all_contacts:
160 self.contacts.add(contact_)
113 contact_panel = VerticalPanel() 161 contact_panel = VerticalPanel()
114 162 contact_panel.add(self.toggle)
115 # checkbox has been replaced by a button
116 self.checkbox = Button("", self.toggleContacts)
117 self.checkbox.getChecked = lambda: self.checkbox.checked if hasattr(self.checkbox, "checked") else None
118 self.checkbox.addStyleName("toggleAssignedContacts")
119 contact_panel.add(self.checkbox)
120 self.contacts = contact.GenericContactList(host)
121 contact_panel.add(self.contacts) 163 contact_panel.add(self.contacts)
122 for contact in self.all_contacts: 164 return contact_panel
123 self.contacts.add(contact) 165
124 self.setWidget(0, 2, contact_panel) 166 def toggleContacts(self, sender=None, showAll=None):
125 167 """Callback for the toggle button"""
126 def refresh():
127 nb_keys = len(self.groups.keys)
128 self.getFlexCellFormatter().setColSpan(nb_keys + 1, 0, 2) # add group panel
129 self.setWidget(nb_keys + 1, 0, self.add_group_panel)
130 self.getFlexCellFormatter().setColSpan(nb_keys + 2, 0, 3) # buttons panel
131 self.setWidget(nb_keys + 2, 0, self.command)
132 self.getFlexCellFormatter().setRowSpan(0, 2, nb_keys + 2) # contact list
133
134 self.groups.setContacts(self.host.contact_panel.groups)
135 refresh()
136 self.restore_contact_panel = False
137 if self.host.contact_panel.getVisible():
138 self.restore_contact_panel = True
139 self.host.panel._contactsSwitch()
140 self.toggleContacts()
141 parent.add(self)
142 parent.setVisible(True)
143 if isinstance(parent, DialogBox):
144 parent.center()
145
146 def toggleContacts(self, sender=None):
147 if sender is None: 168 if sender is None:
148 sender = self.checkbox 169 sender = self.toggle
149 if sender.getChecked(): 170 sender.showAll = showAll if showAll is not None else not sender.showAll
150 sender.checked = False 171 if sender.showAll:
151 sender.setText("Hide assigned") 172 sender.setText("Hide assigned")
152 else: 173 else:
153 sender.checked = True
154 sender.setText("Show assigned") 174 sender.setText("Show assigned")
155 self.updateContactList(sender) 175 self.updateContactList(sender)
156 176
157 def updateContactList(self, sender=None, contact_=None): 177 def updateContactList(self, sender=None, contacts=None):
158 sender = self.checkbox 178 """Update the contact list regarding the toggle button"""
159 if sender.getChecked() is None: 179 if not hasattr(self, "toggle") or not hasattr(self.toggle, "showAll"):
160 # do not update during initialization
161 return 180 return
162 if contact_ is not None: 181 sender = self.toggle
163 if contact_ not in self.all_contacts or not sender.getChecked(): 182 if contacts is not None:
164 return 183 if not isinstance(contacts, list):
165 all_contacts = [contact_] 184 contacts = [contacts]
185 for contact_ in contacts:
186 if contact_ not in self.all_contacts:
187 contacts.remove(contact_)
166 else: 188 else:
167 all_contacts = self.all_contacts 189 contacts = self.all_contacts
168 for contact_ in all_contacts: 190 for contact_ in contacts:
169 if sender.getChecked(): 191 if sender.showAll:
192 self.contacts.getContactLabel(contact_).setVisible(True)
193 else:
170 if contact_ in self.groups.remaining_list: 194 if contact_ in self.groups.remaining_list:
171 self.contacts.getContactLabel(contact_).setVisible(True) 195 self.contacts.getContactLabel(contact_).setVisible(True)
172 else: 196 else:
173 self.contacts.getContactLabel(contact_).setVisible(False) 197 self.contacts.getContactLabel(contact_).setVisible(False)
174 else:
175 self.contacts.getContactLabel(contact_).setVisible(True)
176 198
177 def __close(self): 199 def __close(self):
178 """Remove the widget from parent or close the popup.""" 200 """Remove the widget from parent or close the popup."""
179 if isinstance(self._parent, DialogBox): 201 if isinstance(self._parent, DialogBox):
180 self._parent.hide() 202 self._parent.hide()
192 214
193 _dialog = ConfirmDialog(confirm_cb, text="Do you really want to cancel without saving?") 215 _dialog = ConfirmDialog(confirm_cb, text="Do you really want to cancel without saving?")
194 _dialog.show() 216 _dialog.show()
195 217
196 def closeAndSave(self): 218 def closeAndSave(self):
219 """Call bridge methods to save the changes and close the dialog"""
197 map_ = {} 220 map_ = {}
198 for contact_ in self.all_contacts: 221 for contact_ in self.all_contacts:
199 map_[contact_] = set() 222 map_[contact_] = set()
200 contacts = self.groups.getContacts() 223 contacts = self.groups.getContacts()
201 for group in contacts.keys(): 224 for group in contacts.keys():
202 for contact_ in contacts[group]: 225 for contact_ in contacts[group]:
203 map_[contact_].add(group) 226 try:
227 map_[contact_].add(group)
228 except KeyError:
229 InfoDialog("Invalid contact",
230 "The contact '%s' is not your contact list but it has been assigned to the group '%s'." % (contact_, group) +
231 "Your changes could not be saved: please check your assignments and save again.", Width="400px").center()
232 return
204 for contact_ in map_.keys(): 233 for contact_ in map_.keys():
205 groups = map_[contact_] 234 groups = map_[contact_]
206 current_groups = self.host.contact_panel.getContactGroups(contact_) 235 current_groups = self.host.contact_panel.getContactGroups(contact_)
207 if groups != current_groups: 236 if groups != current_groups:
208 self.host.bridge.call('updateContact', None, contact_, '', list(groups)) 237 self.host.bridge.call('updateContact', None, contact_, '', list(groups))