Mercurial > libervia-web
view src/browser/sat_browser/contact_group.py @ 660:267761bf7f08 frontends_multi_profiles
browser side (contact list): ContactPanels is used instead of OccupantsList in MUC:
- ContactPanels become the generic class for all lists of contacts
- OccupantsList will be removed
- need to implements specials icons (e.g. for games) in ContactBox
- ContactBox now manage a display arguments to set which data we want to display
- ContactsPanel.display renamed to setList
- ContactBox style can be changed when instaciating parent ContactsPanel
- muc_contact CSS class is used for list of MUC occupants
Not fully functionnal yet
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 27 Feb 2015 22:53:27 +0100 |
parents | 6d3142b782c3 |
children | 9877607c719a |
line wrap: on
line source
#!/usr/bin/python # -*- coding: utf-8 -*- # Libervia: a Salut à Toi frontend # Copyright (C) 2013, 2014 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 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 import dialog import list_manager import contact_panel import contact_list unicode = str # FIXME: pyjamas workaround class ContactGroupManager(list_manager.ListManager): def __init__(self, container, keys, contacts, offsets, style): """ @param container (FlexTable): FlexTable parent widget @param keys (dict{unicode: dict{unicode: unicode}}): dict binding items keys to their display config data. @param contacts (list): list of contacts @param offsets (dict): define widgets positions offsets within container: - "x_first": the x offset for the first widget's row on the grid - "x": the x offset for all widgets rows, except the first one if "x_first" is defined - "y": the y offset for all widgets columns on the grid @param style (dict): define CSS styles """ list_manager.ListManager.__init__(self, container, keys, contacts, offsets, style) self.registerPopupMenuPanel(entries={"Remove group": {}}, callback=lambda sender, key: Timer(5, lambda timer: self.removeContactKey(sender, key))) def removeContactKey(self, sender, key): key = sender.getText() def confirm_cb(answer): if answer: list_manager.ListManager.removeItemKey(self, key) self.container.removeKeyFromAddGroupPanel(key) _dialog = dialog.ConfirmDialog(confirm_cb, text="Do you really want to delete the group '%s'?" % key) _dialog.show() def removeFromRemainingList(self, contacts): list_manager.ListManager.removeFromRemainingList(self, contacts) self.container.updateContactList(contacts) def addToRemainingList(self, contacts, ignore_key=None): list_manager.ListManager.addToRemainingList(self, contacts, ignore_key) self.container.updateContactList(contacts) class ContactGroupEditor(DockPanel): """A big panel including a ContactGroupManager and other UI stuff.""" def __init__(self, host, container=None, onCloseCallback=None): """ @param host (SatWebFrontend) @param container (PanelBase): parent panel or None to display in a popup @param onCloseCallback (callable) """ DockPanel.__init__(self) self.host = host # eventually display in a popup if container is None: container = DialogBox(autoHide=False, centered=True) container.setHTML("Manage contact groups") self.container = container self._on_close_callback = onCloseCallback self.all_contacts = contact_list.JIDList(self.host.contact_list.roster_entities) roster_entities_by_group = self.host.contact_list.roster_entities_by_group del roster_entities_by_group[None] # remove the empty group roster_groups = roster_entities_by_group.keys() roster_groups.sort() self.add_group_panel = self.initAddGroupPanel(roster_groups) south_panel = self.initCloseSaveButtons() center_panel = self.initContactGroupManager(roster_groups) east_panel = self.initContactList() 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) # need to be done after the contact list has been initialized self.groups.resetItems(roster_entities_by_group) self.toggleContacts(showAll=True) # Hide the contacts list from the main panel to not confuse the user self.restore_contact_panel = False clist = self.host.contact_list if clist.getVisible(): self.restore_contact_panel = True self.host.panel._contactsSwitch() container.add(self) container.setVisible(True) if isinstance(container, DialogBox): container.center() def initContactGroupManager(self, groups): """Initialise the contact group manager. @param groups (list[unicode]): contact groups """ flex_table = FlexTable() flex_table.addStyleName('contactGroupEditor') # overwrite the default style which has been set for rich text editor style = {"keyItem": "group", "popupMenuItem": "popupMenuItem", "removeButton": "contactGroupRemoveButton", "buttonCell": "contactGroupButtonCell", "keyPanel": "contactGroupPanel" } groups = {group: {} for group in groups} self.groups = ContactGroupManager(flex_table, groups, self.all_contacts, style=style) self.groups.createWidgets() # widgets are automatically added to the 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 def initAddGroupPanel(self, groups): """Initialise the 'Add group' panel. @param groups (list[unicode]): contact groups """ def add_group_cb(key): self.groups.addItemKey(key) self.add_group_panel.textbox.setFocus(True) add_group_panel = dialog.AddGroupPanel(groups, add_group_cb) add_group_panel.addStyleName("addContactGroupPanel") return add_group_panel def initCloseSaveButtons(self): """Add the buttons to close the dialog and save the groups.""" buttons = HorizontalPanel() buttons.addStyleName("marginAuto") buttons.add(Button("Save", listener=self.closeAndSave)) buttons.add(Button("Cancel", listener=self.cancelWithoutSaving)) return buttons def initContactList(self): """Add the contact list to the DockPanel.""" self.toggle = Button("", self.toggleContacts) self.toggle.addStyleName("toggleAssignedContacts") self.contacts = contact_panel.ContactsPanel(self.host) for contact in self.all_contacts: self.contacts.add(contact) panel = VerticalPanel() panel.add(self.toggle) panel.add(self.contacts) return panel def toggleContacts(self, sender=None, showAll=None): """Toggle the button to show contacts and the contact list. @param sender (Button) @param showAll (bool): if set, initialise with True to show all contacts or with False to show only the ones that are not assigned yet. """ self.toggle.showAll = (not self.toggle.showAll) if showAll is None else showAll self.toggle.setText("Hide assigned" if self.toggle.showAll else "Show assigned") self.updateContactList() def updateContactList(self, contacts=None): """Update the contact list's items visibility, depending of the toggle button and the "contacts" attribute. @param contacts (list): contacts to be updated, or None to update all. """ if not hasattr(self, "toggle") or not hasattr(self.toggle, "showAll"): return if contacts is not None: to_remove = set() for contact in contacts: if contact not in self.all_contacts: to_remove.add(contact) for contact in to_remove: contacts.remove(contact) else: contacts = self.all_contacts for contact in contacts: if self.toggle.showAll: self.contacts.getContactBox(contact).setVisible(True) else: if contact in self.groups.items_remaining: self.contacts.getContactBox(contact).setVisible(True) else: self.contacts.getContactBox(contact).setVisible(False) def __close(self): """Remove the widget from parent or close the popup.""" if isinstance(self.container, DialogBox): self.container.hide() self.container.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 = dialog.ConfirmDialog(confirm_cb, text="Do you really want to cancel without saving?") _dialog.show() def closeAndSave(self): """Call bridge methods to save the changes and close the dialog""" old_groups_by_entity = contact_list.JIDDict(self.host.contact_list.roster_groups_by_entity) old_entities = old_groups_by_entity.keys() groups_by_entity = contact_list.JIDDict(self.groups.getKeysByItem()) entities = groups_by_entity.keys() for invalid in entities.difference(self.all_contacts): dialog.InfoDialog("Invalid contact(s)", "The contact '%s' is not in your contact list but has been assigned to: '%s'." % (invalid, "', '".join(groups_by_entity[invalid])) + "Your changes could not be saved: please check your assignments and save again.", Width="400px").center() return for entity in old_entities.difference(entities): self.host.bridge.call('updateContact', None, unicode(entity), '', []) for entity, groups in groups_by_entity.iteritems(): if entity not in old_groups_by_entity or groups != old_groups_by_entity[entity]: self.host.bridge.call('updateContact', None, unicode(entity), '', list(groups)) self.__close()