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