Skip to content

Commit

Permalink
Merge commit 'remotes/luckyluke/contacts'
Browse files Browse the repository at this point in the history
  • Loading branch information
Boris 'billiob' Faure committed Aug 26, 2009
2 parents 3d80ca8 + 07b1222 commit 832d566
Show file tree
Hide file tree
Showing 9 changed files with 456 additions and 23 deletions.
27 changes: 22 additions & 5 deletions amsn2/core/amsn.py
Expand Up @@ -200,10 +200,28 @@ def quit(self):
self._account.signOut()
self._loop.quit()

# TODO: move to UImanager
def addContact(self):
# open a window, get the infos and let the contactlist manager work
account = raw_input('Contact to add: ')
self._contactlist_manager.addContact(account)
def contactCB(account, invite_msg):
if account:
self._contactlist_manager.addContact(account, self._account.view.email,
invite_msg, [])
self._gui.gui.aMSNContactInputWindow(('Contact to add: ', 'Invite message: '),
contactCB, ())

def removeContact(self):
def contactCB(account):
if account:
try:
papyon_contact = self._contactlist_manager._papyon_addressbook.\
contacts.search_by('account', account)[0]
except IndexError:
self._gui.gui.aMSNErrorWindow('You don\'t have the %s contact!', account)
return

self._contactlist_manager.removeContact(papyon_contact.id)

self._gui.gui.aMSNContactDeleteWindow('Contact to remove: ', contactCB, ())

def createMainMenuView(self):
menu = MenuView()
Expand All @@ -216,8 +234,7 @@ def createMainMenuView(self):
mainMenu.addItem(quitMenuItem)

addContactItem = MenuItemView(MenuItemView.COMMAND, label="Add Contact", command=self.addContact)
# only for test purpose, will be called by the contact list
removeContact = MenuItemView(MenuItemView.COMMAND, label='remove contact', command=lambda *args: self._contactlist_manager.removeContact())
removeContact = MenuItemView(MenuItemView.COMMAND, label='Remove contact', command=self.removeContact)

contactsMenu = MenuItemView(MenuItemView.CASCADE_MENU, label="Contacts")
contactsMenu.addItem(addContactItem)
Expand Down
61 changes: 45 additions & 16 deletions amsn2/core/contactlist_manager.py
Expand Up @@ -79,17 +79,25 @@ def addContact(self, account, invite_display_name='amsn2',
self._papyon_addressbook.add_messenger_contact(account, invite_display_name)

def onContactAdded(self, contact):
self.getContact(contact.id, contact)
print 'contact added! %s' % contact
c = self.getContact(contact.id, contact)
gids = [ g.id for g in self.getGroups(contact.id)]
self._addContactToGroups(contact.id, gids)
self._core._gui.gui.aMSNNotificationWindow("Contact %s added!" % contact.account)

def removeContact(self, uid):
self._papyon_addressbook.delete_contact(self._papyon_addressbook.contacts.
def cb_ok():
self._papyon_addressbook.delete_contact(self._papyon_addressbook.contacts.
search_by('id', uid)[0])
# call the UImanager for all the dialogs
self._core._gui.gui.aMSNDialogWindow('Are you sure you want to remove the contact %s?'
% self._papyon_addressbook.contacts.search_by('id', uid)[0].account,
(('OK', cb_ok), ('Cancel', lambda : '')))

def onContactRemoved(self, contact):
# TODO: Fire up a confirmation window, UImanager?
self._removeContactFromGroups(contact.id)
del self._contacts[contact.id]
# TODO: Move to the UImanager
self._core._gui.gui.aMSNNotificationWindow("Contact %s removed!" % contact.account)

''' additional methods '''

Expand All @@ -101,6 +109,17 @@ def _removeContactFromGroups(self, cid):
gv = GroupView(self._core, g.id, g.name, g.contacts)
self._em.emit(self._em.events.GROUPVIEW_UPDATED, gv)

def _addContactToGroups(self, cid, gids):
for gid in gids:
g = self.getGroup(gid)
g.contacts.add(cid)
gv = GroupView(self._core, g.id, g.name, g.contacts)
self._em.emit(self._em.events.GROUPVIEW_UPDATED, gv)

c = self.getContact(cid)
cv = ContactView(self._core, c)
self._em.emit(self._em.events.CONTACTVIEW_UPDATED, cv)

def onCLDownloaded(self, address_book):
self._papyon_addressbook = address_book
grpviews = []
Expand Down Expand Up @@ -199,21 +218,32 @@ def getGroups(self, uid):
everytime
"""
class aMSNContact():
def __init__(self, core, papyon_contact):
def __init__(self, core, papyon_contact=None):
"""
@type core: aMSNCore
@param papyon_contact:
@type papyon_contact: papyon.profile.Contact
"""

self.uid = papyon_contact.id
self.account = ''
self.groups = set()
self.dp = ImageView()
if papyon_contact.msn_object is None:
self.dp.load("Theme", "dp_nopic")
self.icon = ImageView()
self.emblem = ImageView()
self.nickname = StringView()
self.status = StringView()
self.personal_message = StringView()
self.current_media = StringView()
if papyon_contact:
if papyon_contact.msn_object is None:
self.dp.load("Theme", "dp_nopic")
else:
self.dp.load("Theme", "dp_loading")
self.fill(core, papyon_contact)

else:
self.dp.load("Theme", "dp_loading")
self.fill(core, papyon_contact)
self.dp.load("Theme", "dp_nopic")
self.uid = None

def fill(self, core, papyon_contact):
"""
Expand All @@ -223,19 +253,18 @@ def fill(self, core, papyon_contact):
@type papyon_contact: papyon.profile.Contact
"""

self.uid = papyon_contact.id
self.account = papyon_contact.account
self.icon = ImageView()
self.icon.load("Theme","buddy_" + core.p2s[papyon_contact.presence])
self.emblem = ImageView()
self.emblem.load("Theme", "emblem_" + core.p2s[papyon_contact.presence])
#TODO: PARSE ONLY ONCE
self.nickname = StringView()
self.nickname.reset()
self.nickname.appendText(papyon_contact.display_name)
self.personal_message = StringView()
self.personal_message.reset()
self.personal_message.appendText(papyon_contact.personal_message)
self.current_media = StringView()
self.current_media.reset()
self.current_media.appendText(papyon_contact.current_media)
self.status = StringView()
self.status.reset()
self.status.appendText(core.p2s[papyon_contact.presence])

# ro, can be changed indirectly with addressbook's actions
Expand Down
3 changes: 3 additions & 0 deletions amsn2/gui/base/__init__.py
Expand Up @@ -6,3 +6,6 @@
from splash import *
from chat_window import *
from skins import *
from utility import *
from choosers import *

38 changes: 38 additions & 0 deletions amsn2/gui/base/choosers.py
@@ -0,0 +1,38 @@

class aMSNFileChooserWindow(object):
"""
This Interface represent a window used to choose a file,
which could be an image for the dp, a file to send, a theme file, etc.
"""
def __init__(self, filter, directory):
"""
@type filter: tuple
@param filter: A tuple containing strings, that will represent the file
formats to filter.
@type directory: str
@param directory: The path to start from.
This will eventually call the related show() method, so the window is
displayed when created.
"""
raise NotImplementedError

class aMSNDPChooser(object):
"""
This Interface represent a window used to choose a display picture,
should show a list of default dps and the possibility to catch a picture from a webcam.
"""
def __init__(self, default_dps, actions):
"""
@type default_dps: tuple
@params default_dps: a tuple containing strings representing the paths of the default dps.
@type actions: tuple
@param actions: A tuple containing the options between
which the user can choose. Every option is a tuple itself, of the form (name, callback),
where callback is the function that will be called if the option is selected.
This will eventually call the related show() method, so the window is
displayed when created.
"""
raise NotImplementedError

109 changes: 109 additions & 0 deletions amsn2/gui/base/utility.py
@@ -0,0 +1,109 @@

class aMSNErrorWindow(object):
""" This Interface represent an error window """
def __init__(self, error_text):
"""
@type error_text: str
This will eventually call the related show() method, so the window is
displayed when created.
"""
raise NotImplementedError

class aMSNNotificationWindow(object):
"""
This Interface represent a window used to display a notification message,
generally when an operation has finished succesfully.
"""
def __init__(self, notification_text):
"""
@type notification_text: str
This will eventually call the related show() method, so the window is
displayed when created.
"""
raise NotImplementedError

class aMSNDialogWindow(object):
"""
This Interface represent a dialog window, used to ask the user
about something to do.
"""
def __init__(self, message, actions):
"""
@type message: str
@type actions: tuple
@param actions: A tuple containing the options between
which the user can choose. Every option is a tuple itself, of the form (name, callback),
where callback is the function that will be called if the option is selected.
This will eventually call the related show() method, so the window is
displayed when created.
"""
raise NotImplementedError

class aMSNContactInputWindow(object):
"""
This Interface represent a window used to get a new contact.
"""
def __init__(self, message, callback, groups):
"""
@type message: tuple
@param message: A tuple with the messages to be shown in the input window,
of the form (account_string, invite_string).
@type callback: function
@param callback: The function that will be called when the contact info has been filled.
The prototype is callback(email, invite_message, groups).
@type groups: tuple
@param groups: a list of existing groups
"""
raise notImplementedError

class aMSNGroupInputWindow(object):
"""
This Interface represent a window used to get a new group.
"""
def __init__(self, message, callback, contacts):
"""
@type message: tuple
@param message: A tuple with the messages to be shown in the input window.
@type callback: function
@param callback: The function that will be called when the group info has been filled.
The prototype is callback(name_group, contacts).
@type contacts: tuple
@param contacts: a list of existing contacts
"""
raise notImplementedError

class aMSNContactDeleteWindow(object):
"""
This Interface represent a window used to delete a contact.
"""
def __init__(self, message, callback, contacts):
"""
@type message: tuple
@param message: A tuple with the messages to be shown in the window.
@type callback: function
@param callback: The function that will be called when the account has been entered.
The prototype is callback(account), where account is the email of the account to delete.
@type contacts: tuple
@param contacts: a tuple with all the contacts that can be removed in the AddressBook.
"""
raise notImplementedError

class aMSNGroupDeleteWindow(object):
"""
This Interface represent a window used to delete a group.
"""
def __init__(self, message, callback, groups):
"""
@type message: tuple
@param message: A tuple with the messages to be shown in the window.
@type callback: function
@param callback: The function that will be called when the group has been entered.
The prototype is callback(group), where group is the group name.
@type groups: tuple
@param groups: a tuple with all the groups that can be deleted.
"""
raise notImplementedError

39 changes: 39 additions & 0 deletions amsn2/gui/front_ends/gtk/choosers.py
@@ -0,0 +1,39 @@

from amsn2.gui import base
import gtk

class aMSNFileChooserWindow(base.aMSNFileChooserWindow, gtk.FileChooserDialog):
def __init__(self, filter, directory):
"""
@type filter: tuple
@param filter: A tuple containing strings, that will represent the file
formats to filter.
@type directory: str
@param directory: The path to start from.
This will eventually call the related show() method, so the window is
displayed when created.
"""
raise NotImplementedError

class aMSNDPChooser(base.aMSNDPChooser, gtk.Window):
def __init__(self, default_dps, actions):
"""
@type default_dps: tuple
@params default_dps: a tuple containing strings representing the paths of the default dps.
@type actions: tuple
@param actions: A tuple containing the options between
which the user can choose. Every option is a tuple itself, of the form (name, callback),
where callback is the function that will be called if the option is selected.
This will eventually call the related show() method, so the window is
displayed when created.
"""
gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
self.child = None
self.showed = False
self.set_default_size(550, 450)
self.set_position(gtk.WIN_POS_CENTER)
self.set_title("aMSN - Choose a Display Picture")
self.show()

1 change: 0 additions & 1 deletion amsn2/gui/front_ends/gtk/contact_list.py
Expand Up @@ -295,7 +295,6 @@ def onStatusChanged(self, combobox):
if self.status_values[key] == status:
break
# FIXME: changing status to 'offline' will disconnect, so return to login window
# also fix papyon, gives an error on setting 'offline'
if key != self._myview.presence:
self._myview.presence = key

Expand Down
5 changes: 4 additions & 1 deletion amsn2/gui/front_ends/gtk/gtk_.py
Expand Up @@ -5,4 +5,7 @@
from image import *
from splash import *
from skins import *
from chat_window import *
from chat_window import *
from utility import *
from choosers import *

0 comments on commit 832d566

Please sign in to comment.