Mercurial > libervia-web
comparison src/browser/sat_browser/contact_group.py @ 679:a90cc8fc9605
merged branch frontends_multi_profiles
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 18 Mar 2015 16:15:18 +0100 |
parents | 6d3142b782c3 |
children | 9877607c719a |
comparison
equal
deleted
inserted
replaced
590:1bffc4c244c3 | 679:a90cc8fc9605 |
---|---|
26 from pyjamas.ui.DialogBox import DialogBox | 26 from pyjamas.ui.DialogBox import DialogBox |
27 from pyjamas.ui import HasAlignment | 27 from pyjamas.ui import HasAlignment |
28 | 28 |
29 import dialog | 29 import dialog |
30 import list_manager | 30 import list_manager |
31 import contact | 31 import contact_panel |
32 import contact_list | |
33 | |
34 | |
35 unicode = str # FIXME: pyjamas workaround | |
32 | 36 |
33 | 37 |
34 class ContactGroupManager(list_manager.ListManager): | 38 class ContactGroupManager(list_manager.ListManager): |
35 """A manager for sub-panels to assign contacts to each group.""" | 39 |
36 | 40 def __init__(self, container, keys, contacts, offsets, style): |
37 def __init__(self, parent, keys_dict, contact_list, offsets, style): | 41 """ |
38 list_manager.ListManager.__init__(self, parent, keys_dict, contact_list, offsets, style) | 42 @param container (FlexTable): FlexTable parent widget |
43 @param keys (dict{unicode: dict{unicode: unicode}}): dict binding items | |
44 keys to their display config data. | |
45 @param contacts (list): list of contacts | |
46 @param offsets (dict): define widgets positions offsets within container: | |
47 - "x_first": the x offset for the first widget's row on the grid | |
48 - "x": the x offset for all widgets rows, except the first one if "x_first" is defined | |
49 - "y": the y offset for all widgets columns on the grid | |
50 @param style (dict): define CSS styles | |
51 """ | |
52 list_manager.ListManager.__init__(self, container, keys, contacts, offsets, style) | |
39 self.registerPopupMenuPanel(entries={"Remove group": {}}, | 53 self.registerPopupMenuPanel(entries={"Remove group": {}}, |
40 callback=lambda sender, key: Timer(5, lambda timer: self.removeContactKey(sender, key))) | 54 callback=lambda sender, key: Timer(5, lambda timer: self.removeContactKey(sender, key))) |
41 | 55 |
42 def removeContactKey(self, sender, key): | 56 def removeContactKey(self, sender, key): |
43 key = sender.getText() | 57 key = sender.getText() |
44 | 58 |
45 def confirm_cb(answer): | 59 def confirm_cb(answer): |
46 if answer: | 60 if answer: |
47 list_manager.ListManager.removeContactKey(self, key) | 61 list_manager.ListManager.removeItemKey(self, key) |
48 self._parent.removeKeyFromAddGroupPanel(key) | 62 self.container.removeKeyFromAddGroupPanel(key) |
49 | 63 |
50 _dialog = dialog.ConfirmDialog(confirm_cb, text="Do you really want to delete the group '%s'?" % key) | 64 _dialog = dialog.ConfirmDialog(confirm_cb, text="Do you really want to delete the group '%s'?" % key) |
51 _dialog.show() | 65 _dialog.show() |
52 | 66 |
53 def removeFromRemainingList(self, contacts): | 67 def removeFromRemainingList(self, contacts): |
54 list_manager.ListManager.removeFromRemainingList(self, contacts) | 68 list_manager.ListManager.removeFromRemainingList(self, contacts) |
55 self._parent.updateContactList(contacts=contacts) | 69 self.container.updateContactList(contacts) |
56 | 70 |
57 def addToRemainingList(self, contacts, ignore_key=None): | 71 def addToRemainingList(self, contacts, ignore_key=None): |
58 list_manager.ListManager.addToRemainingList(self, contacts, ignore_key) | 72 list_manager.ListManager.addToRemainingList(self, contacts, ignore_key) |
59 self._parent.updateContactList(contacts=contacts) | 73 self.container.updateContactList(contacts) |
60 | 74 |
61 | 75 |
62 class ContactGroupEditor(DockPanel): | 76 class ContactGroupEditor(DockPanel): |
63 """Panel for the contact groups manager.""" | 77 """A big panel including a ContactGroupManager and other UI stuff.""" |
64 | 78 |
65 def __init__(self, host, parent=None, onCloseCallback=None): | 79 def __init__(self, host, container=None, onCloseCallback=None): |
80 """ | |
81 | |
82 @param host (SatWebFrontend) | |
83 @param container (PanelBase): parent panel or None to display in a popup | |
84 @param onCloseCallback (callable) | |
85 """ | |
66 DockPanel.__init__(self) | 86 DockPanel.__init__(self) |
67 self.host = host | 87 self.host = host |
68 | 88 |
69 # eventually display in a popup | 89 # eventually display in a popup |
70 if parent is None: | 90 if container is None: |
71 parent = DialogBox(autoHide=False, centered=True) | 91 container = DialogBox(autoHide=False, centered=True) |
72 parent.setHTML("Manage contact groups") | 92 container.setHTML("Manage contact groups") |
73 self._parent = parent | 93 self.container = container |
74 self._on_close_callback = onCloseCallback | 94 self._on_close_callback = onCloseCallback |
75 self.all_contacts = self.host.contact_panel.getContacts() | 95 |
76 | 96 self.all_contacts = contact_list.JIDList(self.host.contact_list.roster_entities) |
77 groups_list = self.host.contact_panel.groups.keys() | 97 roster_entities_by_group = self.host.contact_list.roster_entities_by_group |
78 groups_list.sort() | 98 del roster_entities_by_group[None] # remove the empty group |
79 | 99 roster_groups = roster_entities_by_group.keys() |
80 self.add_group_panel = self.getAddGroupPanel(groups_list) | 100 roster_groups.sort() |
81 south_panel = self.getCloseSaveButtons() | 101 |
82 center_panel = self.getContactGroupManager(groups_list) | 102 self.add_group_panel = self.initAddGroupPanel(roster_groups) |
83 east_panel = self.getContactList() | 103 south_panel = self.initCloseSaveButtons() |
104 center_panel = self.initContactGroupManager(roster_groups) | |
105 east_panel = self.initContactList() | |
84 | 106 |
85 self.add(self.add_group_panel, DockPanel.CENTER) | 107 self.add(self.add_group_panel, DockPanel.CENTER) |
86 self.add(east_panel, DockPanel.EAST) | 108 self.add(east_panel, DockPanel.EAST) |
87 self.add(center_panel, DockPanel.NORTH) | 109 self.add(center_panel, DockPanel.NORTH) |
88 self.add(south_panel, DockPanel.SOUTH) | 110 self.add(south_panel, DockPanel.SOUTH) |
95 self.setCellHorizontalAlignment(self.add_group_panel, HasAlignment.ALIGN_LEFT) | 117 self.setCellHorizontalAlignment(self.add_group_panel, HasAlignment.ALIGN_LEFT) |
96 self.setCellVerticalAlignment(south_panel, HasAlignment.ALIGN_BOTTOM) | 118 self.setCellVerticalAlignment(south_panel, HasAlignment.ALIGN_BOTTOM) |
97 self.setCellHorizontalAlignment(south_panel, HasAlignment.ALIGN_CENTER) | 119 self.setCellHorizontalAlignment(south_panel, HasAlignment.ALIGN_CENTER) |
98 | 120 |
99 # need to be done after the contact list has been initialized | 121 # need to be done after the contact list has been initialized |
100 self.groups.setContacts(self.host.contact_panel.groups) | 122 self.groups.resetItems(roster_entities_by_group) |
101 self.toggleContacts(showAll=True) | 123 self.toggleContacts(showAll=True) |
102 | 124 |
103 # Hide the contacts list from the main panel to not confuse the user | 125 # Hide the contacts list from the main panel to not confuse the user |
104 self.restore_contact_panel = False | 126 self.restore_contact_panel = False |
105 if self.host.contact_panel.getVisible(): | 127 clist = self.host.contact_list |
128 if clist.getVisible(): | |
106 self.restore_contact_panel = True | 129 self.restore_contact_panel = True |
107 self.host.panel._contactsSwitch() | 130 self.host.panel._contactsSwitch() |
108 | 131 |
109 parent.add(self) | 132 container.add(self) |
110 parent.setVisible(True) | 133 container.setVisible(True) |
111 if isinstance(parent, DialogBox): | 134 if isinstance(container, DialogBox): |
112 parent.center() | 135 container.center() |
113 | 136 |
114 def getContactGroupManager(self, groups_list): | 137 def initContactGroupManager(self, groups): |
115 """Set the list manager for the groups""" | 138 """Initialise the contact group manager. |
116 flex_table = FlexTable(len(groups_list), 2) | 139 |
140 @param groups (list[unicode]): contact groups | |
141 """ | |
142 flex_table = FlexTable() | |
117 flex_table.addStyleName('contactGroupEditor') | 143 flex_table.addStyleName('contactGroupEditor') |
144 | |
118 # overwrite the default style which has been set for rich text editor | 145 # overwrite the default style which has been set for rich text editor |
119 style = { | 146 style = {"keyItem": "group", |
120 "keyItem": "group", | 147 "popupMenuItem": "popupMenuItem", |
121 "popupMenuItem": "popupMenuItem", | 148 "removeButton": "contactGroupRemoveButton", |
122 "removeButton": "contactGroupRemoveButton", | 149 "buttonCell": "contactGroupButtonCell", |
123 "buttonCell": "contactGroupButtonCell", | 150 "keyPanel": "contactGroupPanel" |
124 "keyPanel": "contactGroupPanel" | 151 } |
125 } | 152 |
126 self.groups = ContactGroupManager(flex_table, groups_list, self.all_contacts, style=style) | 153 groups = {group: {} for group in groups} |
127 self.groups.createWidgets() # widgets are automatically added to FlexTable | 154 self.groups = ContactGroupManager(flex_table, groups, self.all_contacts, style=style) |
155 self.groups.createWidgets() # widgets are automatically added to the FlexTable | |
156 | |
128 # FIXME: clean that part which is dangerous | 157 # FIXME: clean that part which is dangerous |
129 flex_table.updateContactList = self.updateContactList | 158 flex_table.updateContactList = self.updateContactList |
130 flex_table.removeKeyFromAddGroupPanel = self.add_group_panel.groups.remove | 159 flex_table.removeKeyFromAddGroupPanel = self.add_group_panel.groups.remove |
160 | |
131 return flex_table | 161 return flex_table |
132 | 162 |
133 def getAddGroupPanel(self, groups_list): | 163 def initAddGroupPanel(self, groups): |
134 """Add the 'Add group' panel to the FlexTable""" | 164 """Initialise the 'Add group' panel. |
135 | 165 |
136 def add_group_cb(text): | 166 @param groups (list[unicode]): contact groups |
137 self.groups.addContactKey(text) | 167 """ |
168 | |
169 def add_group_cb(key): | |
170 self.groups.addItemKey(key) | |
138 self.add_group_panel.textbox.setFocus(True) | 171 self.add_group_panel.textbox.setFocus(True) |
139 | 172 |
140 add_group_panel = dialog.AddGroupPanel(groups_list, add_group_cb) | 173 add_group_panel = dialog.AddGroupPanel(groups, add_group_cb) |
141 add_group_panel.addStyleName("addContactGroupPanel") | 174 add_group_panel.addStyleName("addContactGroupPanel") |
142 return add_group_panel | 175 return add_group_panel |
143 | 176 |
144 def getCloseSaveButtons(self): | 177 def initCloseSaveButtons(self): |
145 """Add the buttons to close the dialog / save the groups""" | 178 """Add the buttons to close the dialog and save the groups.""" |
146 buttons = HorizontalPanel() | 179 buttons = HorizontalPanel() |
147 buttons.addStyleName("marginAuto") | 180 buttons.addStyleName("marginAuto") |
148 buttons.add(Button("Save", listener=self.closeAndSave)) | 181 buttons.add(Button("Save", listener=self.closeAndSave)) |
149 buttons.add(Button("Cancel", listener=self.cancelWithoutSaving)) | 182 buttons.add(Button("Cancel", listener=self.cancelWithoutSaving)) |
150 return buttons | 183 return buttons |
151 | 184 |
152 def getContactList(self): | 185 def initContactList(self): |
153 """Add the contact list to the DockPanel""" | 186 """Add the contact list to the DockPanel.""" |
154 self.toggle = Button("", self.toggleContacts) | 187 self.toggle = Button("", self.toggleContacts) |
155 self.toggle.addStyleName("toggleAssignedContacts") | 188 self.toggle.addStyleName("toggleAssignedContacts") |
156 self.contacts = contact.GenericContactList(self.host) | 189 self.contacts = contact_panel.ContactsPanel(self.host) |
157 for contact_ in self.all_contacts: | 190 for contact in self.all_contacts: |
158 self.contacts.add(contact_) | 191 self.contacts.add(contact) |
159 contact_panel = VerticalPanel() | 192 panel = VerticalPanel() |
160 contact_panel.add(self.toggle) | 193 panel.add(self.toggle) |
161 contact_panel.add(self.contacts) | 194 panel.add(self.contacts) |
162 return contact_panel | 195 return panel |
163 | 196 |
164 def toggleContacts(self, sender=None, showAll=None): | 197 def toggleContacts(self, sender=None, showAll=None): |
165 """Callback for the toggle button""" | 198 """Toggle the button to show contacts and the contact list. |
166 if sender is None: | 199 |
167 sender = self.toggle | 200 @param sender (Button) |
168 sender.showAll = showAll if showAll is not None else not sender.showAll | 201 @param showAll (bool): if set, initialise with True to show all contacts |
169 if sender.showAll: | 202 or with False to show only the ones that are not assigned yet. |
170 sender.setText("Hide assigned") | 203 """ |
171 else: | 204 self.toggle.showAll = (not self.toggle.showAll) if showAll is None else showAll |
172 sender.setText("Show assigned") | 205 self.toggle.setText("Hide assigned" if self.toggle.showAll else "Show assigned") |
173 self.updateContactList(sender) | 206 self.updateContactList() |
174 | 207 |
175 def updateContactList(self, sender=None, contacts=None): | 208 def updateContactList(self, contacts=None): |
176 """Update the contact list regarding the toggle button""" | 209 """Update the contact list's items visibility, depending of the toggle |
210 button and the "contacts" attribute. | |
211 | |
212 @param contacts (list): contacts to be updated, or None to update all. | |
213 """ | |
177 if not hasattr(self, "toggle") or not hasattr(self.toggle, "showAll"): | 214 if not hasattr(self, "toggle") or not hasattr(self.toggle, "showAll"): |
178 return | 215 return |
179 sender = self.toggle | |
180 if contacts is not None: | 216 if contacts is not None: |
181 if not isinstance(contacts, list): | 217 to_remove = set() |
182 contacts = [contacts] | 218 for contact in contacts: |
183 for contact_ in contacts: | 219 if contact not in self.all_contacts: |
184 if contact_ not in self.all_contacts: | 220 to_remove.add(contact) |
185 contacts.remove(contact_) | 221 for contact in to_remove: |
222 contacts.remove(contact) | |
186 else: | 223 else: |
187 contacts = self.all_contacts | 224 contacts = self.all_contacts |
188 for contact_ in contacts: | 225 for contact in contacts: |
189 if sender.showAll: | 226 if self.toggle.showAll: |
190 self.contacts.getContactBox(contact_).setVisible(True) | 227 self.contacts.getContactBox(contact).setVisible(True) |
191 else: | 228 else: |
192 if contact_ in self.groups.remaining_list: | 229 if contact in self.groups.items_remaining: |
193 self.contacts.getContactBox(contact_).setVisible(True) | 230 self.contacts.getContactBox(contact).setVisible(True) |
194 else: | 231 else: |
195 self.contacts.getContactBox(contact_).setVisible(False) | 232 self.contacts.getContactBox(contact).setVisible(False) |
196 | 233 |
197 def __close(self): | 234 def __close(self): |
198 """Remove the widget from parent or close the popup.""" | 235 """Remove the widget from parent or close the popup.""" |
199 if isinstance(self._parent, DialogBox): | 236 if isinstance(self.container, DialogBox): |
200 self._parent.hide() | 237 self.container.hide() |
201 self._parent.remove(self) | 238 self.container.remove(self) |
202 if self._on_close_callback is not None: | 239 if self._on_close_callback is not None: |
203 self._on_close_callback() | 240 self._on_close_callback() |
204 if self.restore_contact_panel: | 241 if self.restore_contact_panel: |
205 self.host.panel._contactsSwitch() | 242 self.host.panel._contactsSwitch() |
206 | 243 |
213 _dialog = dialog.ConfirmDialog(confirm_cb, text="Do you really want to cancel without saving?") | 250 _dialog = dialog.ConfirmDialog(confirm_cb, text="Do you really want to cancel without saving?") |
214 _dialog.show() | 251 _dialog.show() |
215 | 252 |
216 def closeAndSave(self): | 253 def closeAndSave(self): |
217 """Call bridge methods to save the changes and close the dialog""" | 254 """Call bridge methods to save the changes and close the dialog""" |
218 map_ = {} | 255 old_groups_by_entity = contact_list.JIDDict(self.host.contact_list.roster_groups_by_entity) |
219 for contact_ in self.all_contacts: | 256 old_entities = old_groups_by_entity.keys() |
220 map_[contact_] = set() | 257 groups_by_entity = contact_list.JIDDict(self.groups.getKeysByItem()) |
221 contacts = self.groups.getContacts() | 258 entities = groups_by_entity.keys() |
222 for group in contacts.keys(): | 259 |
223 for contact_ in contacts[group]: | 260 for invalid in entities.difference(self.all_contacts): |
224 try: | 261 dialog.InfoDialog("Invalid contact(s)", |
225 map_[contact_].add(group) | 262 "The contact '%s' is not in your contact list but has been assigned to: '%s'." % (invalid, "', '".join(groups_by_entity[invalid])) + |
226 except KeyError: | 263 "Your changes could not be saved: please check your assignments and save again.", Width="400px").center() |
227 dialog.InfoDialog("Invalid contact", | 264 return |
228 "The contact '%s' is not your contact list but it has been assigned to the group '%s'." % (contact_, group) + | 265 |
229 "Your changes could not be saved: please check your assignments and save again.", Width="400px").center() | 266 for entity in old_entities.difference(entities): |
230 return | 267 self.host.bridge.call('updateContact', None, unicode(entity), '', []) |
231 for contact_ in map_.keys(): | 268 |
232 groups = map_[contact_] | 269 for entity, groups in groups_by_entity.iteritems(): |
233 current_groups = self.host.contact_panel.getContactGroups(contact_) | 270 if entity not in old_groups_by_entity or groups != old_groups_by_entity[entity]: |
234 if groups != current_groups: | 271 self.host.bridge.call('updateContact', None, unicode(entity), '', list(groups)) |
235 self.host.bridge.call('updateContact', None, contact_, '', list(groups)) | |
236 self.__close() | 272 self.__close() |