# HG changeset patch # User souliane # Date 1383986385 -3600 # Node ID 0e7f3944bd278a268ecda38c6c54e69b75fe7197 # Parent da0487f0a2e740821b51e7cf2e9816c72e681bf7 browser_side: added contact group manager based on ListManager diff -r da0487f0a2e7 -r 0e7f3944bd27 browser_side/contact_group.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/browser_side/contact_group.py Sat Nov 09 09:39:45 2013 +0100 @@ -0,0 +1,209 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Libervia: a Salut à Toi frontend +Copyright (C) 2013 Adrien Cossa + +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 . +""" + +from pyjamas.ui.FlexTable import FlexTable +from browser_side.dialog import ConfirmDialog +from list_manager import ListManager +import contact +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 +import dialog + + +class ContactGroupManager(ListManager): + """A manager for sub-panels to assign contacts to each group.""" + + def __init__(self, parent, keys_dict, contact_list, offsets, style): + ListManager.__init__(self, parent, keys_dict, contact_list, offsets, style) + self.registerPopupMenuPanel(entries={"Remove group": {}}, + callback=lambda sender, key: Timer(5, lambda: self.removeContactKey(sender, key))) + + def removeContactKey(self, sender, key): + key = sender.getText() + + 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) + + _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 addToRemainingList(self, contact_): + ListManager.addToRemainingList(self, contact_) + self._parent.updateContactList(contact_=contact_) + + +class ContactGroupEditor(FlexTable): + """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 + self.host = host + if parent is None: + parent = DialogBox(autoHide=False, centered=True) + parent.setHTML("Manage contact groups") + + self._parent = parent + self._on_close_callback = onCloseCallback + + groups_list = self.host.contact_panel.groups.keys() + groups_list.sort() + FlexTable.__init__(self, len(groups_list) + 2, 3) + self.addStyleName('contactGroupEditor') + + 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() + + # overwrite the default style which has been set for rich text editor + style = { + "keyItem": "group", + "popupMenuItem": "popupMenuItem", + "removeButton": "contactGroupRemoveButton", + "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)) + + contact_panel = VerticalPanel() + + # 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 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 + + 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 toggleContacts(self, sender=None): + if sender is None: + sender = self.checkbox + if sender.getChecked(): + sender.checked = False + 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 + return + if contact_ is not None: + if contact_ not in self.all_contacts or not sender.getChecked(): + return + all_contacts = [contact_] + else: + all_contacts = self.all_contacts + for contact_ in all_contacts: + if sender.getChecked(): + 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.""" + if isinstance(self._parent, DialogBox): + self._parent.hide() + self._parent.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 = ConfirmDialog(confirm_cb, text="Do you really want to cancel without saving?") + _dialog.show() + + def closeAndSave(self): + 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) + for contact_ in map_.keys(): + groups = map_[contact_] + current_groups = self.host.contact_panel.getContactGroups(contact_) + if groups != current_groups: + self.host.bridge.call('updateContact', None, contact_, '', list(groups)) + self.__close() diff -r da0487f0a2e7 -r 0e7f3944bd27 browser_side/list_manager.py --- a/browser_side/list_manager.py Sat Nov 09 15:31:39 2013 +0100 +++ b/browser_side/list_manager.py Sat Nov 09 09:39:45 2013 +0100 @@ -86,6 +86,7 @@ self.style = { "keyItem": "recipientTypeItem", + "popupMenuItem": "recipientTypeItem", "buttonCell": "recipientButtonCell", "dragoverPanel": "dragover-recipientPanel", "keyPanel": "recipientPanel", @@ -110,7 +111,7 @@ def _addChild(self, entry, title_format): """Add a button and FlowPanel for the corresponding map entry.""" button = Button(title_format % entry["title"]) - button.addStyleName(self.style["keyItem"]) + button.setStyleName(self.style["keyItem"]) if hasattr(entry, "desc"): button.setTitle(entry["desc"]) if not "optional" in entry: @@ -211,7 +212,7 @@ def registerPopupMenuPanel(self, entries, hide, callback): "Register a popup menu panel that will be bound to all contact keys elements." - self.popup_menu = panels.PopupMenuPanel(entries=entries, hide=hide, callback=callback, item_style="recipientTypeItem") + self.popup_menu = panels.PopupMenuPanel(entries=entries, hide=hide, callback=callback, item_style=self.style["popupMenuItem"]) class DragAutoCompleteTextBox(AutoCompleteTextBox, DragWidget, MouseHandler): @@ -427,6 +428,9 @@ def setContacts(self, tab): """Set the contacts.""" self.emptyContacts() + if isinstance(tab, set): + tab = list(tab) + tab.sort() for contact in tab: self.addContact(contact, resetLastTextBox=False) self.__resetLastTextBox() diff -r da0487f0a2e7 -r 0e7f3944bd27 browser_side/menu.py --- a/browser_side/menu.py Sat Nov 09 15:31:39 2013 +0100 +++ b/browser_side/menu.py Sat Nov 09 09:39:45 2013 +0100 @@ -40,6 +40,7 @@ from xmlui import XMLUI import panels import dialog +from contact_group import ContactGroupEditor import re @@ -138,12 +139,13 @@ menu_general.addItem("Disconnect", MenuCmd(self, "onDisconnect")) menu_contacts = MenuBar(vertical=True) - menu_contacts.addItem("add contact", MenuCmd(self, "onAddContact")) - menu_contacts.addItem("update contact", MenuCmd(self, "onUpdateContact")) - menu_contacts.addItem("remove contact", MenuCmd(self, "onRemoveContact")) + menu_contacts.addItem("Add contact", MenuCmd(self, "onAddContact")) + menu_contacts.addItem("Update contact", MenuCmd(self, "onUpdateContact")) + menu_contacts.addItem("Remove contact", MenuCmd(self, "onRemoveContact")) + menu_contacts.addItem("Manage groups", MenuCmd(self, "onManageContactGroups")) menu_group = MenuBar(vertical=True) - menu_group.addItem("join room", MenuCmd(self, "onJoinRoom")) + menu_group.addItem("Join room", MenuCmd(self, "onJoinRoom")) menu_group.addItem("Collective radio", MenuCmd(self, "onCollectiveRadio")) menu_games = MenuBar(vertical=True) @@ -278,6 +280,14 @@ _dialog = dialog.GenericConfirmDialog([_contacts_list], dialogCb, "Who do you want to remove from your contacts ?") _dialog.show() + def onManageContactGroups(self): + """Open the contact groups manager.""" + + def onCloseCallback(): + pass + + ContactGroupEditor(self.host, None, onCloseCallback) + #Group menu def onJoinRoom(self): _dialog = None diff -r da0487f0a2e7 -r 0e7f3944bd27 public/libervia.css --- a/public/libervia.css Sat Nov 09 15:31:39 2013 +0100 +++ b/public/libervia.css Sat Nov 09 09:39:45 2013 +0100 @@ -1257,3 +1257,37 @@ cursor: pointer; border-radius: 5px; } + +/* Contact group manager */ + +.contactGroupEditor { + width: 800px; + max-width:800px; + min-width: 800px; + margin-top: 9px; + margin-left:18px; +} + +.contactGroupRemoveButton { + margin: 0px 10px 0px 0px; + padding: 0px; + border: 1px dashed red; + border-radius: 5px 5px 5px 5px; +} + +.addContactGroupPanel { + +} + +.contactGroupPanel { + vertical-align:middle; +} + +.toggleAssignedContacts { + white-space: nowrap; +} + +.contactGroupButtonCell { + vertical-align: baseline; + width: 55px; +} \ No newline at end of file