All pastes #840158 Raw Edit

Stuff

public python v1 · immutable
#840158 ·published 2007-12-31 15:25 UTC
rendered paste body
# -*- coding: utf-8 -*-#   This file is part of emesene.##    Emesene is free software; you can redistribute it and/or modify#    it under the terms of the GNU General Public License as published by#    the Free Software Foundation; either version 2 of the License, or#    (at your option) any later version.##    emesene 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 General Public License for more details.##    You should have received a copy of the GNU General Public License#    along with emesene; if not, write to the Free Software#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USAimport gtkimport timeimport pangoimport gobjectimport webkitgtkimport reimport UserListimport SmilieWindowfrom Theme import resizePixbufimport emesenelib.commonimport emesenelib.ContactDataimport Widgetsclass WebkitRenderer(webkitgtk.WebView):    def __init__(self,themepath,header,footer,variant=False):        webkitgtk.WebView.__init__(self)        self.themepath=themepath        self.header=header        self.footer=footer        if variant and variant != 'Default':            varianttext = "</style>\n\<style id=\"mainStyle\" type=\"text/css\" media=\"screen,print\">\n\	@import url(\"Variants/"+variant+".css\");\n\</style>\n"        else:            varianttext=''        self.oldhtml="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n\\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n\<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\<head>\n\<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\n\" />\n\<base href=\""+self.themepath+"/\">\n\<style id=\"baseStyle\" type=\"text/css\" media=\"screen,print\">\n\	@import url(\"main.css\");\n\	*{ word-wrap:break-word; }\n\</style>\n\"+varianttext+"</head>\n\<body>\n\"+self.header+"\n\<div id=\"Chat\">"        self.load_html_string(self.oldhtml+"</div>"+self.footer+"</body>\</html>", self.themepath)            def display_html(self,html, consecutive=False):        #TODO: Find a less ugly and more performant way to do this, maybe using DOM/JS?        if consecutive:                    regexhax = re.compile( '<(?:span|div) id="insert"(?:\s+/)?.*>(?:.*</(?:span|div)>)?' )            insertpos = regexhax.findall( self.oldhtml )[0]            self.newcontent = self.oldhtml.rpartition( insertpos )[0] + html + self.oldhtml.rpartition( insertpos )[2]        else:            self.newcontent=self.oldhtml+html        self.load_html_string(self.newcontent+"</div>"+self.footer+"</body></html>", self.themepath)        self.oldhtml=self.newcontent        def get_buffer(self):        return self.oldhtml    class ConversationUI(gtk.VBox):    '''this class represent all the widgets that are inside a tab    also hold the tab widget because there is no better place than    this to hold it...'''        def __init__(self, controller, parentConversation):        gtk.VBox.__init__(self)                self.parentConversation = parentConversation        self.controller = controller        self.config = self.controller.config                # the header that contain the nick, the PM, status etc        self.header = Header(self, controller)        # the widget that contain the tabs and the conversations        self.tabWidget = TabWidget(self, controller)        # the widget where you can put the text        self.input = InputWidget(self, controller, \            parentConversation.isCurrent)        # the status bar        self.status = gtk.Statusbar()        # the toolbar        self.toolbar = ToolbarWidget(self, controller)        self.toolbar.set_style(gtk.TOOLBAR_ICONS)        self.toolbar.set_small(self.config.user['smallIcons'])        self.toolbarinput = gtk.HBox()        # the list of users when we are on a group chat        self.listOfUsers = UserList.UserList(self.controller, \            self.controller.getTheme(), self.config, False)                # the scroll for the list of users        self.scrollList = gtk.ScrolledWindow()        self.scrollList.set_shadow_type(gtk.SHADOW_IN)        self.scrollList.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)        self.scrollList.set_size_request(116, -1)        self.scrollList.set_border_width(0)        self.scrollList.add(self.listOfUsers)        # the scroll for the textview below        self.scroll = gtk.ScrolledWindow()        self.scroll.set_shadow_type(gtk.SHADOW_IN)        self.scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)                # the widget where the conversation is shown        self.textview=WebkitRenderer(self.controller.getConversationLayoutManager().theme['basepath'],self.controller.getConversationLayoutManager().theme['header'], self.controller.getConversationLayoutManager().theme['footer'], self.config.user['layoutvariant'])                self.scroll.add(self.textview)        # Friends avatar                #self.imageFrame = gtk.AspectFrame()        self.image = Widgets.avatarHolder(cellKeyPosition = gtk.ANCHOR_NORTH)        contact = self.controller.getContact(\            self.parentConversation.switchboard.firstUser)        self.image.set_from_pixbuf(\            self.controller.getTheme().getUserDisplayPicture(contact))        #self.imageFrame.add(self.image)        self.controller.msn.connect('display-picture-changed', self.displayPictureChanged)        self.controller.msn.connect('user-attr-changed', self.onUserAttrChanged)                self.hidebutton = gtk.Button()        self.hidebutton.connect('clicked', self.hideShowButton)        self.hidebutton.set_relief(gtk.RELIEF_NONE)        self.hidebuttonArrow = Widgets.TinyArrow(gtk.ARROW_RIGHT)        self.hidebutton.add(self.hidebuttonArrow)                # Vbox to pack both the userlist and friend display image        self.vbox = gtk.VBox()        self.vbox.pack_start(self.image, False,False,0)        self.vbox.pack_start(self.scrollList, True, True)        self.vbox.set_border_width(0)        self.filler = gtk.VBox()        self.filler.set_border_width(0)        self.vbox2 = gtk.VBox()        self.vbox2.set_border_width(0)        self.vbox2.pack_start(self.hidebutton, False, False)        self.vbox2.pack_start(self.filler, True, True)        # HBox to pack the VBox above and the Hide/Show Friends Avatar button        self.hboxFrame = gtk.HBox()        self.hboxFrame.set_border_width(0)        self.hboxFrame.pack_start(self.vbox, True, True)        self.hboxFrame.pack_start(self.vbox2, False, True)        self.hpaned = gtk.HBox()        self.hpaned.pack_start(self.scroll, True, True,2)        self.hpaned.pack_start(self.hboxFrame, False, False,2)        # the hbox that pack the textview, the images of the other users        # and the userlist        self.hbox = gtk.HBox()        self.hbox.set_border_width(2)        self.hbox.pack_start(self.hpaned, True, True)                self.toolbarinputVbox = gtk.VBox()        self.toolbarinputVbox.pack_start(self.toolbar, False, True)        self.toolbarinputVbox.pack_start(self.input, True, True)        self.toolbarinput.pack_start(self.toolbarinputVbox, True, True)        self.toolbarinput.connect('size-allocate', self.onToolbarinputResize)        # the vertical panel that divide the textview and the input         # (toolbar and input)        self.vpaned = gtk.VPaned()        self.vpaned.pack1(self.hbox, True, True)        self.vpaned.pack2(self.toolbarinput, False, True)                self.transfers = FtBarWidget(self.controller, self,                                         parentConversation)                self.pack_start(self.header, False, False)        self.pack_start(self.vpaned, True, True)        self.pack_start(self.transfers, False, False)        self.pack_start(self.status, False, False)              self.messageWaiting = {}        self.contactTyping = {}        self.typingTimeoutID = 0        self.closed = False        self.last_mark = None        #self.input.grabFocus()        self.show_all()                self.update()            def onToolbarinputResize(self, *args):        alloc = self.toolbarinput.get_allocation()        self.config.user['convInputHeight'] = alloc.height           def onTextviewKeyPress(self, widget, event):        # don't focus inputbox if Control is pressed (Ctrl-C etc.)        if event.keyval == gtk.keysyms.Control_L or \                event.keyval == gtk.keysyms.Control_R or \                event.state & gtk.gdk.CONTROL_MASK:            return        self.input.input.emit('key-press-event', event)        self.input.grabFocus()        def close(self):        self.closed = True        def setInputEnabled(self, enable):        self.input.input.set_sensitive(enable)        def onUserAttrChanged(self, msn, contact):        if contact.email in self.parentConversation.getMembers():            self.update()        def noneIsTyping(self):        try:            for contact in self.email_list:                if self.contactTyping[contact] == True:                    return False            return True        except:            return False                def update(self):        self.header.update()        self.tabWidget.update()        self.input.update()        self.email_list = [mail.email for mail in self.parentConversation.getMembersDict().values()]                # add new user in conversation        for email in self.email_list:            if email not in self.contactTyping.keys():                self.contactTyping[email] = False            if email not in self.messageWaiting.keys():                self.messageWaiting[email] = False                for email in self.contactTyping.keys():            if self.contactTyping[email]:                self.setTyping(email)            else:                self.setDefault(email)        isGroupChat = len(self.parentConversation.getMembers()) > 1                if isGroupChat:            members = self.parentConversation.getMembersDict()            d = {'members' : emesenelib.ContactData.Group('members')}            for member in members.values():                d['members'].setUser(member.email, member)            self.listOfUsers.fill(d)        # if you want to show the avatar and hide the grouplist or        # viceversa first do the hide and then the show, because this methods        # also hide the container vbox to not let an empty widget there        if isGroupChat:            self.hideAvatar()            self.hidebutton.hide()            self.showUserList()        elif self.config.user['showAvatars']:            self.hidebutton.show()            self.hideUserList()            if self.config.user['showAvatarOther']:                self.hidebuttonArrow.set(gtk.ARROW_RIGHT, gtk.SHADOW_NONE)                self.showAvatar()            else:                self.hidebuttonArrow.set(gtk.ARROW_LEFT, gtk.SHADOW_NONE)                self.hideAvatar()        else:            self.hideAvatar()            self.hideUserList()            self.hidebutton.hide()                    if not self.config.user['showHeader']:            self.header.hide()        else:            self.header.show()        if not self.config.user['showToolbar']:            self.toolbar.hide()        else:            self.toolbar.show()                if not self.config.user['showTabCloseButton']:            self.tabWidget.closeButton.hide()        else:            self.tabWidget.closeButton.show()                inputHeight = self.config.user['convInputHeight']        self.toolbarinput.set_size_request(-1, inputHeight)    def scrollToBottom(self):        '''scroll to the end of the conversation'''        #not working yet, don't ask me why        temp = self.scroll.get_vadjustment()        temp.set_value(temp.upper-temp.page_size)        print temp.upper, temp.page_size, temp.value        self.scroll.set_vadjustment(temp)        #textbuffer = self.textview.get_buffer()        #mark = textbuffer.create_mark("end", textbuffer.get_end_iter(), False)        #if self.last_mark:         #   textiter = textbuffer.get_iter_at_mark(self.last_mark)         #   rect = self.textview.get_visible_rect()        #    pos = rect.y + rect.height        #     if (pos + 25) < self.textview.get_iter_location(textiter).y:       #         return                #self.last_mark = mark        #self.textview.scroll_to_mark(mark, 0.05, True, 0.0, 1.0)        #textbuffer.place_cursor(textbuffer.get_end_iter())            def showUserList(self):        self.vbox.show()        self.scrollList.show_all()        self.listOfUsers.show()            def hideUserList(self):        self.vbox.hide()        self.scrollList.hide()        self.listOfUsers.hide()    def showAvatar(self):        self.vbox.show()        self.image.show_all()    def hideAvatar(self):        self.vbox.hide()        self.image.hide()            def hideShowButton(self, *args):        if self.hidebuttonArrow.arrow_type == gtk.ARROW_LEFT:            self.hidebuttonArrow.set(gtk.ARROW_RIGHT, gtk.SHADOW_NONE)            if len(self.parentConversation.getMembers()) > 1:                self.showUserList()            else:                self.showAvatar()                self.config.user['showAvatarOther'] = True        else:            self.hidebuttonArrow.set(gtk.ARROW_LEFT, gtk.SHADOW_NONE)            if len(self.parentConversation.getMembers()) > 1:                self.hideUserList()            else:                self.hideAvatar()                self.config.user['showAvatarOther'] = False        def rebuildStatusText(self):        '''Builds the text displayed in the statusbar, based in        self.contactTyping. The "output" is a comma separated list        of (full) mails and "is/are typing a message..." '''        mails = [x for x in self.contactTyping.keys() \                  if self.contactTyping[x] == True]        string = ''        if len(mails) > 0:            comma = ', ' # TODO: gettext?            for mail in mails:                string += str(mail) + comma                            # yes, i know we don't need to deal with utf-8 here, but...            string = str(unicode(string)[:-len(comma)])                        if len(mails) == 1:                string += ' ' + _('is typing a message...')            else:                string += ' ' + _('are typing a message...')        #this is a hack to skip the statusbar stack        self.status.get_children()[0].get_children()[0].set_text(string)    def setMessageWaiting(self, mail):        if self.parentConversation.getIsCurrent():            return self.setDefault(mail)        self.tabWidget.setMessageWaiting()        self.header.setDefault()        if mail:            self.contactTyping[mail] = False            self.messageWaiting[mail] = True            self.rebuildStatusText()            def setTyping(self, mail):        if self.messageWaiting.has_key(mail) and self.messageWaiting[mail]: return        self.header.setTyping()        self.tabWidget.setTyping()                self.contactTyping[mail] = True        self.rebuildStatusText()        if self.typingTimeoutID > 0:            gobject.source_remove(self.typingTimeoutID)        self.typingTimeoutID = gobject.timeout_add(8000, \            self.clearTyping, mail)    def clearTyping(self, mail):        if self.messageWaiting[mail]:            self.setMessageWaiting(mail)        else:            self.setDefault(mail)        self.contactTyping[mail] = False        return False    def setDefault(self, mail):        #if self.noneIsTyping():         self.tabWidget.setDefault()        self.header.setDefault()        if mail:            self.contactTyping[mail] = False            self.messageWaiting[mail] = False            self.rebuildStatusText()    def displayPictureChanged(self, msnp, switchboard, msnobj, email):        if self.parentConversation.getSwitchboard().firstUser == email:            contact = self.controller.msn.contactManager.getContact(email)            self.image.set_from_pixbuf(                self.controller.getTheme().getUserDisplayPicture(contact))        # TODO: getters    def getTextView(self):        return self.textview        def getParentConversation(self):        return self.parentConversation                class Header(gtk.HBox):    '''the header of the conversation'''        def __init__(self, parentUI, controller):        '''Contructor'''        gtk.HBox.__init__(self)        self.parentUI = parentUI        self.controller = controller        self.config = controller.config        self.set_border_width(6)        self.set_spacing(6)        self.parser = controller.unifiedParser                self.statusImage = gtk.Image()        self.statusImage.set_from_pixbuf(self.controller.getTheme().getImage('groupChat'))                self.label = gtk.Label()                self.label.set_selectable(True)        self.label.unset_flags(gtk.CAN_FOCUS)                self.label.set_alignment(0.0, 0.5)        self.label.set_line_wrap(True)        self.label.set_ellipsize(pango.ELLIPSIZE_END)        # when someone fin how to make that this label is selected all the time,        # discoment the next line        #self.label.set_selectable(True)                        self.label.set_markup('<b><i>' + _('Connecting...') + '</i></b>')                self.reconnect = gtk.Button(_('Reconnect'))        self.reconnect.connect('clicked', self.reconnectClicked)        self.pack_start(self.statusImage, False, False)        self.pack_start(self.label)        self.pack_start(self.reconnect, False, False)        self.statusImage.show()        self.label.show()        self.show()            def reconnectClicked(self, button):        self.parentUI.parentConversation.reconnect()        self.reconnect.hide()        def update(self):        conversation = self.parentUI.parentConversation        members = conversation.getMembersDict()        if self.config.user['showTabImageStatus']:            self.statusImage.hide()            return        if conversation.switchboard.status == 'error':            self.setLabel()        elif len(members) == 1:            contact = members.values()[0]            self.statusImage.set_from_pixbuf(self.controller.getTheme().statusToPixbuf(contact.status))        else:            self.statusImage.set_from_pixbuf(self.controller.getTheme().getImage('userPanel'))    def setTyping(self):        typingColor = self.config.user['typingColor']        styleOpen = "<b><span foreground='" + typingColor + "'>"        styleClose = "</span></b>"        self.setLabel(styleOpen, styleClose)        def setLabel(self, styleOpen='<b>', styleClose='</b>'):        conversation = self.parentUI.parentConversation        members = conversation.getMembersDict()        personalMessageColor = self.config.user['personalMessageColor']        switchboard = conversation.switchboard        if switchboard.status == 'error':            self.text = '%s<i> %s (%d) </i>%s' % \                (styleOpen, _('Can\'t connect'), switchboard.error, styleClose)            self.label.set_markup(self.text)            self.reconnect.show()            return        self.reconnect.hide()        if len(members) == 1:            contact = members.values()[0]            self.text = styleOpen + emesenelib.common.escape(contact.nick) + styleClose                        if len(contact.personalMessage) > 0:                self.text += "\n<span foreground='" + personalMessageColor + "'>"                self.text += emesenelib.common.escape(contact.personalMessage) + "</span>"                    self.text += "\n<span foreground='" + personalMessageColor + "'>"            self.text += contact.email + "</span>"        elif len(members) > 1:            self.text = styleOpen + _('Group chat') + styleClose            self.text += "\n<span foreground='" + personalMessageColor + "'>"            self.text += str(len(members)) + ' ' + _('Members') + "</span>"            self.statusImage.set_from_pixbuf(self.controller.getTheme().getImage('groupChat'))        else:            self.text = styleOpen + '<i>' + _('Connecting...') + '</i>' + styleClose                        self.label.set_markup(self.text)              def setDefault(self):        self.setLabel()        class TabWidget(gtk.HBox):    '''this class represent the widget that is inside the tab    it contains a label and a close button'''        def __init__(self, parentUI, controller):        '''Contructor'''        gtk.HBox.__init__(self)        self.parentUI = parentUI        self.controller = controller        self.config = controller.config        self.text = self.parentUI.parentConversation.getTitle()                self.label = gtk.Label()        self.label.set_use_markup(True)        self.label.set_markup(self.text)        self.label.set_ellipsize(pango.ELLIPSIZE_END)                img = gtk.Image()        img.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)                self.closeButton = gtk.Button()        self.closeButton.set_image(img)        self.closeButton.set_relief(gtk.RELIEF_NONE)                self.statusImage = gtk.Image()                self.pack_start(self.statusImage, False, False)        self.pack_start(self.label)        self.pack_start(self.closeButton, False, False)        self.show_all()        self.closeButton.connect('clicked', self.onCloseClicked)        def onCloseClicked(self, button):        self.parentUI.parentConversation.close()            def update(self):        title = self.parentUI.parentConversation.getTitle()        members = self.parentUI.parentConversation.getMembersDict()                if not title == '':            self.text = title        if not self.config.user['showTabImageStatus']:            return        if len(members) == 1:            contact = members.values()[0]            basepixbuf = self.controller.theme.statusToPixbuf(contact.status)        else:            basepixbuf = self.controller.theme.getImage('userPanel')        self.statusImage.set_from_pixbuf(resizePixbuf(basepixbuf, 16, 16))    def setDefault(self):        self.label.set_markup(self.text)            def setTyping(self):        typingColor = self.config.user['typingColor']        self.label.set_markup('<span foreground="%s">%s</span>' % (typingColor, self.text))        def setMessageWaiting(self):        messageWaitingColor = self.config.user['messageWaitingColor']        self.label.set_markup('<span foreground="%s">%s</span>' % (messageWaitingColor, self.text))    class LocalAvatar(gtk.HBox):    def __init__(self, parentUI, controller):        gtk.HBox.__init__(self)                self.parentUI = parentUI        self.controller = controller        self.config = controller.config                self.hidebutton = gtk.Button()        self.hidebutton.connect('clicked', self.hideShowButton)            self.hidebutton.set_relief(gtk.RELIEF_NONE)        self.hidebuttonArrow = Widgets.TinyArrow(gtk.ARROW_RIGHT)        self.hidebutton.add(self.hidebuttonArrow)                self.localimage = Widgets.avatarHolder(cellKeyPosition = gtk.ANCHOR_SOUTH)        self.imageEventBox = gtk.EventBox()        self.imageEventBox.set_events(gtk.gdk.BUTTON_PRESS_MASK)        self.imageEventBox.set_visible_window(False)        self.imageEventBox.connect('button-press-event', self.changeAvatar)        self.imageEventBox.add(self.localimage)                if self.controller.avatar != None:            self.localimage.set_from_pixbuf(self.controller.avatar.getImage())        else:            self.pixbuf = self.controller.theme.getImage('icon96')            self.localimage.set_from_pixbuf(self.pixbuf)                self.controller.connect('avatar-changed', self.localDisplayPictureChanged)                self.filler = gtk.VBox()                self.vboxButtonFrame = gtk.VBox()        self.vboxButtonFrame.pack_start(self.hidebutton, False, False)        self.vboxButtonFrame.pack_start(self.filler, True, True)                self.filler2 = gtk.VBox()                self.vboxAvatarFrame = gtk.VBox()        self.vboxAvatarFrame.pack_start(self.imageEventBox, False, False)        self.vboxAvatarFrame.pack_start(self.filler2, True, True)                self.pack_start(self.vboxAvatarFrame, False, False, 0)        self.pack_start(self.vboxButtonFrame, False, False, 0)        self.update()            def update(self):        if self.config.user['showAvatars']:            self.hidebutton.show()            if not self.config.user['showAvatarMine']:                self.imageEventBox.hide()                self.hidebuttonArrow.set(gtk.ARROW_LEFT, gtk.SHADOW_NONE)            else:                self.imageEventBox.show()                self.hidebuttonArrow.set(gtk.ARROW_RIGHT, gtk.SHADOW_NONE)        else:            self.imageEventBox.hide()            self.hidebutton.hide()            def displayPictureChanged(self, msnp, email):        if self.parentUI.parentConversation.getSwitchboard().firstUser == email:            #self.image.set_from_pixbuf(self.controller.getTheme().getUserDisplayPicture(email))              print 'check here because self.image soesnt exist (ConversationUI 720)'    def localDisplayPictureChanged(self, controller):        self.localimage.set_from_pixbuf(self.controller.avatar.getImage())     def changeAvatar(self, widget, event):        self.controller.changeAvatarDialog()                def hideShowButton(self, *args):        if self.config.user['showAvatars']:            self.hidebutton.show()            if self.config.user['showAvatarMine']:                self.hidebuttonArrow.set(gtk.ARROW_LEFT, gtk.SHADOW_NONE)                self.imageEventBox.hide()                self.config.user['showAvatarMine'] = False            else:                self.hidebuttonArrow.set(gtk.ARROW_RIGHT, gtk.SHADOW_NONE)                self.imageEventBox.show()                self.config.user['showAvatarMine'] = True        else:            self.imageEventBox.hide()            self.hidebutton.hide()class InputWidget(gtk.HBox):    '''This class represents the input widgets (text entry) and avatar (if enabled)'''    def __init__(self, parentUI, controller, setFocus=True):        gtk.HBox.__init__(self)        self.parentUI = parentUI        self.controller = controller        self.config = controller.config        self.lastKeyPressed = 0        self.history = []        self.historyIndex = -1        self.set_border_width(2)        # the local avatar        self.localAvatar = LocalAvatar(self, controller)        self.input = Widgets.inputBox()        self.input.set_left_margin(6)        self.input.set_right_margin(6)        self.input.set_wrap_mode(gtk.WRAP_WORD_CHAR)                self.inputBuffer = self.input.get_buffer()                self.scrollInput = gtk.ScrolledWindow()        self.scrollInput.set_policy(gtk.POLICY_AUTOMATIC,                                     gtk.POLICY_AUTOMATIC)        self.scrollInput.add(self.input)                frameInput = gtk.Frame()        frameInput.add(self.scrollInput)        self.pack_start(frameInput, True, True, 2)        self.pack_start(self.localAvatar, False, False, 2)        self.inputBuffer.connect('changed', self.on_changed_event)        self.input.connect('key-press-event' , self.on_key_press_event)        self.input.connect_after('message-send', self.message_send)        self.input.connect_after('escape-pressed',                                     self.on_escape_pressed_event)                self.input.connect_after('map-event', self.on_input_map_event)                if setFocus:            self.input.grab_focus()                self.tag = None        self.id_timeout = None        self.parse_off = 0        self.applyAttrsToInput()        self.show_all()    def update(self):        '''update the inner componnents if needed'''        self.localAvatar.update()    def transformEmo(self, *args):        ''' transform smiley shorcuts in pixbuf '''        if not self.controller.config.user['parseSmilies']:            print "XXX HAI"            return        theme = self.controller.theme        emos = []        customEmo = self.controller.customEmoticons                for code in theme.getSmileysList():            iter_start = self.inputBuffer.get_start_iter()            iter_start.set_offset(self.parse_off)            while iter_start.forward_search(code,                                 gtk.TEXT_SEARCH_VISIBLE_ONLY):                iter_pos, iter_end = iter_start.forward_search(code, \                    gtk.TEXT_SEARCH_VISIBLE_ONLY)                pixbuf = theme.getSmiley(code, False)                pixbuf.shortcut = code                                tag = gtk.TextTag()                tag.set_property('invisible', True)                tagtable = self.inputBuffer.get_tag_table()                tagtable.add(tag)                self.inputBuffer.apply_tag(tag, iter_pos, iter_end)                                mark1 = self.inputBuffer.create_mark(None, iter_pos)                mark2 = self.inputBuffer.create_mark(None, iter_end)                                img = gtk.Image()                img.set_from_pixbuf(pixbuf)                img.show()                img.shortcut = code                                emos.append((img, mark1, mark2))                iter_start = iter_end        for code, filename in customEmo.list.iteritems():            iter_start = self.inputBuffer.get_start_iter()            iter_start.set_offset(self.parse_off)            while iter_start.forward_search(code,                                             gtk.TEXT_SEARCH_VISIBLE_ONLY):                iter_pos,iter_end = iter_start.forward_search(code, \                    gtk.TEXT_SEARCH_VISIBLE_ONLY)                pixbuf = gtk.gdk.pixbuf_new_from_file(filename)                pixbuf = resizePixbuf(pixbuf, 24, 24)                                                tag =  gtk.TextTag()                tag.set_property('invisible', True)                tagtable = self.inputBuffer.get_tag_table()                tagtable.add(tag)                self.inputBuffer.apply_tag(tag, iter_pos, iter_end)                                mark1 = self.inputBuffer.create_mark(None, iter_pos)                mark2 = self.inputBuffer.create_mark(None, iter_end)                                img = gtk.Image()                img.set_from_pixbuf(pixbuf)                img.show()                img.shortcut = code                                emos.append((img, mark1, mark2))                iter_start = iter_end                for emo in emos:            iterStart = self.inputBuffer.get_iter_at_mark(emo[1])            iterEnd = self.inputBuffer.get_iter_at_mark(emo[2])            self.inputBuffer.delete(iterStart, iterEnd)            iterStart = self.inputBuffer.get_iter_at_mark(emo[1])            #self.inputBuffer.insert_pixbuf(iterStart, emo[0])                        anchor = self.inputBuffer.create_child_anchor(iterStart)                                    self.input.add_child_at_anchor(emo[0], anchor)                    iter_off = self.inputBuffer.get_end_iter()        if iter_off.inside_word() or iter_off.ends_word():            iter_off.backward_word_start()        self.parse_off = iter_off.get_offset()        def grabFocus(self):        self.input.grab_focus()             def getBuffer(self):        return self.inputBuffer        def clearMessageInput(self):        self.setInputText('')        return True        def sendMessage(self):        if self.getInputText() != '':            # Message size is limited so we must truncate it to send             # it in several parts            message = self.getInputText()                        self.parentUI.parentConversation.sendMessage(message)            self.setInputText('')            self.history.append(message)            self.historyIndex = -1        return True        def setInputText(self , string , tag = None):        if tag == None:            self.inputBuffer.set_text(string)        else:            pass            def getInputText(self):        '''return the text in the input textview'''        iterStart, iterEnd = self.inputBuffer.get_bounds()        text = self.inputBuffer.get_slice(iterStart, iterEnd)        emos = []        #TODO: magic string '\xef\xbf\xbc'        while iterStart.forward_search('\xef\xbf\xbc', \            gtk.TEXT_SEARCH_VISIBLE_ONLY):            iterPos,iterEnd = iterStart.forward_search('\xef\xbf\xbc', \                gtk.TEXT_SEARCH_VISIBLE_ONLY)            if iterPos.get_child_anchor().get_widgets():                shortcut = iterPos.get_child_anchor().get_widgets()[0].shortcut                emos.append(shortcut)            #shortcut = iterPos.get_child_anchor().shortcut                        iterStart = iterEnd        for emo in emos:            text = text.replace('\xef\xbf\xbc', emo, 1)                    return text    def appendInputText(self, text, tag = None):        '''append the given text to the inputBuffer, if tag != None insert        with the given tag'''        self.inputBuffer.insert_at_cursor(text)            def on_changed_event(self, *args):        '''Method called when text is inserted in the textbuffer (typing)        First, it checks if the message length is >= 5 or if        the message is a slash command ("^\/[^\/]" is confusing)        Then, checks the last key pressed time, and if it's more        than 5 seconds, send a typing message'''                  if self.inputBuffer.get_start_iter().get_offset() < self.parse_off:            self.parse_off = 0        if self.id_timeout != None:            gobject.source_remove(self.id_timeout)                if not self.getInputText().startswith('/'):            self.id_timeout = gobject.timeout_add(200, self.transformEmo)                text = self.getInputText()        if len(text) < 5 or (text[0] == '/' and text[1] != '/'):            return self.updateInputFormat()                # sents user typing notification        actualTime = int(time.time())                if (actualTime - self.lastKeyPressed) > 5 and \           self.config.user['sendTyping']:            self.lastKeyPressed = actualTime            try:                self.parentUI.parentConversation.sendIsTyping()            except Exception , e:                print str(e)                        self.updateInputFormat()                    def applyAttrsToInput(self):        '''apply the current attributes to the text in input'''        self.tag = self.parentUI.parentConversation.getTextTag()        self.inputBuffer.get_tag_table().add(self.tag)        self.tag.set_property('left-margin', 6)        self.tag.set_priority(self.inputBuffer.get_tag_table().get_size() - 1)        self.inputBuffer.apply_tag(self.tag,                                            self.inputBuffer.get_start_iter(),                                            self.inputBuffer.get_end_iter())                self.controller.emit('input-format-changed', self.input)            def updateInputFormat(self):        if self.tag != None:            self.inputBuffer.apply_tag(self.tag,                                        self.inputBuffer.get_start_iter(),                                        self.inputBuffer.get_end_iter())            def message_send(self, widget):        if self.id_timeout != None:            gobject.source_remove(self.id_timeout)            self.id_timeout = None        return self.sendMessage()    def on_input_map_event(self, widget, event):        if self.parentUI.getParentConversation().getIsCurrent():            self.input.grab_focus()     def on_escape_pressed_event(self, widget):        if not self.parentUI.closed:            self.parentUI.parentConversation.close()    def on_key_press_event(self , widget, event):        if event.keyval == gtk.keysyms.space:            if self.id_timeout != None:                gobject.source_remove(self.id_timeout)                self.id_timeout = None            if not self.getInputText().startswith('/'):                self.transformEmo()        elif event.keyval in (gtk.keysyms.Up, gtk.keysyms.Down) and \            (event.state & gtk.gdk.CONTROL_MASK):            up = event.keyval == gtk.keysyms.Up                        if up and self.historyIndex == -1 and len(self.history) > 0:                self.historyIndex = len(self.history) - 1                if self.getInputText() != '':                    self.history.append(self.getInputText())                        elif self.historyIndex > 0 and self.historyIndex < len(self.history):                if up: self.historyIndex -= 1                else: self.historyIndex += 1                        if self.historyIndex > -1 and self.historyIndex < len(self.history):                self.setInputText(self.history[self.historyIndex])            elif self.historyIndex != -1:                self.setInputText('')class ToolbarWidget(gtk.Toolbar):    '''This represents a toolbar that contains text formatation, smilies buttom, do nudge button,    and so on...'''        def __init__(self, parentUI, controller):        gtk.Toolbar.__init__(self)        self.parentUI = parentUI        self.controller = controller        self.config = controller.config        self.smilieWindow = SmilieWindow.SmilieWindow(self.controller, \                                                       self.smilieSelected, \                                                       None)        self.fontFace = gtk.ToolButton()        self.fontFace.set_stock_id(gtk.STOCK_SELECT_FONT)        self.fontFace.connect('clicked', self.on_font_face_clicked)                self.fontColor = gtk.ToolButton()        self.fontColor.set_stock_id(gtk.STOCK_SELECT_COLOR)        self.fontColor.connect('clicked', self.on_font_color_clicked)                self.boldButton = gtk.ToggleToolButton()        self.boldButton.set_stock_id(gtk.STOCK_BOLD)        self.boldButton.connect('toggled', self.toggled, 'bold')        self.boldButton.set_active(self.config.user['fontBold'])                self.italicButton = gtk.ToggleToolButton()        self.italicButton.set_stock_id(gtk.STOCK_ITALIC)        self.italicButton.connect('toggled', self.toggled, 'italic')        self.italicButton.set_active(self.config.user['fontItalic'])        self.underlineButton = gtk.ToggleToolButton()        self.underlineButton.set_stock_id(gtk.STOCK_UNDERLINE)        self.underlineButton.connect('toggled', self.toggled, 'underline')        self.underlineButton.set_active(self.config.user['fontUnderline'])        self.strikeButton = gtk.ToggleToolButton()        self.strikeButton.set_stock_id(gtk.STOCK_STRIKETHROUGH)        self.strikeButton.connect('toggled', self.toggled, 'strike')        self.strikeButton.set_active(self.config.user['fontStrike'])                        self.smilieButton = gtk.ToolButton()        self.smilieButton.set_label(_('Smilie'))        self.smilieButton.connect('clicked', self.showSmilieWindow)                self.nudgeButton = gtk.ToolButton()        self.nudgeButton.set_label(_('Nudge'))        self.nudgeButton.connect('clicked', self.doNudge)        self.inviteButton = gtk.ToolButton()        self.inviteButton.set_label(_('Invite'))        self.inviteButton.set_stock_id(gtk.STOCK_ADD)        self.inviteButton.connect('clicked', self.showInviteDialog)                #clear conversation toolbar button        imgclear = gtk.Image()        imgclear.set_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_LARGE_TOOLBAR)        self.clearButton = gtk.ToolButton(imgclear, _('Clear Conversation'))        self.clearButton.connect('clicked', self.clearOutputText)        # Add buttons to the toolbar        self.insert(self.fontFace, -1)        self.insert(self.fontColor, -1)        self.insert(self.boldButton, -1)        self.insert(self.italicButton, -1)        self.insert(self.underlineButton, -1)        self.insert(self.strikeButton, -1)                self.insert(gtk.SeparatorToolItem(), -1)                self.insert(self.smilieButton, -1)        self.insert(self.nudgeButton, -1)        self.insert(gtk.SeparatorToolItem(), -1)        self.insert(self.inviteButton, -1)        self.insert(self.clearButton, -1)        # Set tooltips to buttons        self.tooltips = gtk.Tooltips()        self.tooltips.enable()        self.fontFace.set_tooltip(self.tooltips, _('Font selection'))        self.fontColor.set_tooltip(self.tooltips, _('Font color selection'))        self.boldButton.set_tooltip(self.tooltips, _('Bold'))        self.italicButton.set_tooltip(self.tooltips, _('Italic'))        self.underlineButton.set_tooltip(self.tooltips, _('Underline'))        self.strikeButton.set_tooltip(self.tooltips, _('Strike'))        self.smilieButton.set_tooltip(self.tooltips, _('Insert a smilie'))        self.nudgeButton.set_tooltip(self.tooltips, _('Send nudge'))        self.inviteButton.set_tooltip(self.tooltips, \            _('Invite a friend to the conversation'))        self.clearButton.set_tooltip(self.tooltips, _('Clear conversation'))                self.show_all()            def on_font_face_clicked(self, *args):        '''Called when user clicks on the font selection button        in the toolbar'''        self.parentUI.parentConversation.parentConversationWindow.changeFont()        def on_font_color_clicked(self, *args):        ''' Called when user clicks on the color selection button in the toolbar'''        self.parentUI.parentConversation.parentConversationWindow.changeColor()        def toggled(self, button, option):        '''callback for the toggled signal'''        if option == 'bold':            self.config.user['fontBold'] = button.get_active()        elif option == 'italic':            self.config.user['fontItalic'] = button.get_active()        elif option == 'underline':            self.config.user['fontUnderline'] = button.get_active()        elif option == 'strike':            self.config.user['fontStrike'] = button.get_active()        self.parentUI.input.applyAttrsToInput()        def set_small(self, value):        '''sets the icons size to small if value is True'''        if value:            size = gtk.ICON_SIZE_MENU        else:            size = gtk.ICON_SIZE_LARGE_TOOLBAR        imgSmilie = gtk.Image()        imgNudge = gtk.Image()                nudge = self.controller.theme.getImage('nudge')        grin = self.controller.theme.getSmiley(':D')        if isinstance(grin, gtk.gdk.PixbufAnimation):            grin = grin.get_static_image()                grin = resizePixbuf(grin, *gtk.icon_size_lookup(size))        nudge = resizePixbuf(nudge, *gtk.icon_size_lookup(size))        imgSmilie.set_from_pixbuf(grin)        imgNudge.set_from_pixbuf(nudge)        self.smilieButton.set_icon_widget(imgSmilie)        self.nudgeButton.set_icon_widget(imgNudge)                # set the global icons size         settings = self.get_settings()        settings.set_long_property('gtk-toolbar-icon-size', size, \            'emesene:ConversationUI')            def setFontBold(self, value):        self.boldButton.set_active(value)    def setFontUnderline(self, value):        self.underlineButton.set_active(value)            def setFontStrike(self, value):        self.strikeButton.set_active(value)            def setFontItalic(self, value):        self.italicButton.set_active(value)                    def smilieSelected(self, smilie=None):        '''this method is called when the user click a smilie in the        smiliewindow'''        if smilie:            self.parentUI.input.appendInputText(smilie)        self.parentUI.input.grabFocus()            def showSmilieWindow(self, *args):        '''this method is called when the user click the smilie button'''        self.smilieWindow.show()            def showInviteDialog(self, *args):        '''this method is called when the user click the invite button'''        conv = self.parentUI.parentConversation        dictionary = conv.contactManager.getOnlineUsersDict()        members = {}                for i in conv.getMembers() + [conv.getUser()]:            members[i] = self.controller.getContact(i)                    InviteWindow(self.controller, None, dictionary, members,                         self.controller.theme, conv.inviteUser).run()              def clearOutputText(self, *args):        self.parentUI.parentConversation.textBuffer.set_text('')            def doNudge(self, *args):        '''this method is called when the user click the nudge button'''        self.parentUI.parentConversation.doNudge()      def doBlock(self, *args):        '''this method is called when the user clicks the block button'''        users = self.parentUI.parentConversation.getMembers()        if len(users) == 1:            self.controller.blockUser(users[0])     def doUnblock(self, *args):        '''this method is called when the user clicks the block button'''        users = self.parentUI.parentConversation.getMembers()        if len(users) == 1:            self.controller.unblockUser(users[0])   class InviteWindow(gtk.Dialog):    '''This class represent a list where the user can pick wich users     he want to invite to a conversation'''    def __init__(self, controller, father, onlineUsers,                     usersInConversation, theme, callback):        '''Constructor callback is called when a user is selected with         double click'''        gtk.Dialog.__init__(self, _('Invite'), father,                     gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,                     (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, \                     gtk.STOCK_ADD, gtk.RESPONSE_ACCEPT))        self.set_default_size(400, 300)        self.callback = callback        users = onlineUsers                self.controller = controller                for i in usersInConversation.keys():            if users.has_key(i):                del users[i]        self.userList = UserList.UserList(self.controller, theme, self.controller.config, False)        self.userList.connect('item-selected', self.userListClicked)                group = emesenelib.ContactData.Group(_('Users'))                for contact in controller.msn.contactManager.contacts.values():            if contact.status != 'FLN' and contact.email not in usersInConversation:                group.setUser(contact.email, contact)                    self.userList.fill({group.name : group})                self.scroll = gtk.ScrolledWindow()        self.scroll.set_policy(gtk.POLICY_AUTOMATIC , gtk.POLICY_AUTOMATIC)        self.scroll.add(self.userList)                self.connect('response', self.invite)        self.connect('delete-event', self.close)        self.vbox.pack_start(self.scroll)        self.vbox.show_all()            def invite(self, dialog, response_id):        '''get the user in the userlist and call the callback'''        try:            if response_id == gtk.RESPONSE_ACCEPT:                self.userListClicked(self.userList, self.userList.getSelected())                return True            else:                self.close()                return False        except Exception, e:            print e                def userListClicked(self, userList, t):        if t and t[0] == 'user':            self.callback(t[1].email)            self.close()        def close(self, *args):        '''close the window'''        self.hide()class FtBarWidget(gtk.HBox):    '''bar which represents active file transfers'''        def __init__(self, controller, parentUI, parentConversation):                gtk.HBox.__init__(self)                self.controller = controller        self.parentUI = parentUI        self.parentConversation = parentConversation        self.show_all()            def add(self, transfer):        widget = FtWidget(self.controller, self, transfer)        transfer.ui = widget                self.pack_start(widget, False, False)        self.show_all()        class FtWidget(gtk.HBox):    '''this class represents the ui widget for one filetransfer'''    def __init__(self, controller, transferBar, transfer):        gtk.HBox.__init__(self)                self.controller = controller        self.transferBar = transferBar        self.transfer = transfer        self.eventBox = gtk.EventBox()        self.progress = gtk.ProgressBar()        self.progress.set_ellipsize(pango.ELLIPSIZE_END)                self.eventBox.add(self.progress)        self.pack_start(self.eventBox, False, False)                self.buttons = []        self.show_all()        self.tooltip = FileTransferTooltip(self.eventBox, self.transfer)        self.eventBox.connect('event', self.onProgressBarEvent)                self.updateProgress()        self.stateChanged()    def onProgressBarEvent(self, widget, event):        if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1 and \                self.transfer.state == self.transfer.RECEIVED:            self.transfer.open()        def updateProgress(self):        self.progress.set_fraction(self.transfer.getFraction())        self.progress.set_text(self.transfer.getFilename())        self.tooltip.update()    def stateChanged(self):        state = self.transfer.state        # remove existing buttons                for button in self.buttons:            self.remove(button)                self.buttons = []                if state == self.transfer.WAITING:            button = gtk.Button(None, None)            button.set_image(self.getButtonImage(gtk.STOCK_APPLY))            button.connect('clicked', self.onAcceptClicked)            self.buttons.append(button)                if state in (self.transfer.RECEIVED, self.transfer.FAILED):            button = gtk.Button(None, None)            button.set_image(self.getButtonImage(gtk.STOCK_CLOSE))            button.connect('clicked', self.onCloseClicked)            self.buttons.append(button)                if state == self.transfer.WAITING or state == self.transfer.TRANSFERING:            cancelButton = gtk.Button(None, None)            cancelButton.connect('clicked', self.onCancelClicked)            cancelButton.set_image(self.getButtonImage(gtk.STOCK_CANCEL))            self.buttons.append(cancelButton)                for button in self.buttons:            self.pack_start(button, False, False)                self.show_all()        self.updateProgress()    def getButtonImage(self, stockImage):        img = gtk.Image()        img.set_from_stock(stockImage, gtk.ICON_SIZE_MENU)        return img    def onCancelClicked(self, widget):        self.transfer.cancel()            def onAcceptClicked(self, widget):        self.transfer.accept()            def onCloseClicked(self, widget):        self.transfer.remove()        self.transferBar.remove(self)DELAY = 500class FileTransferTooltip(gtk.Window):    '''Class that implements the filetransfer tooltip'''    def __init__(self, parentWidget, transfer):        gtk.Window.__init__(self, gtk.WINDOW_POPUP)        self.transfer = transfer                self.set_name('gtk-tooltips')        self.set_position(gtk.WIN_POS_MOUSE)        self.set_resizable(False)        self.set_border_width(4)        self.set_app_paintable(True)                self.image = gtk.Image()        self.details = gtk.Label()        self.details.set_alignment(0, 0)                self.table = gtk.Table(3, 2, False)        self.table.set_col_spacings(5)                self.addLabel(_('Status:'), 0, 1, 0, 1)        self.addLabel(_('Average speed:'), 0, 1, 1, 2)        self.addLabel(_('Time elapsed:'), 0, 1, 2, 3)                self.status = gtk.Label()        self.speed = gtk.Label()        self.elapsed = gtk.Label()                self.addLabel('', 1, 2, 0, 1, self.status)        self.addLabel('', 1, 2, 1, 2, self.speed)        self.addLabel('', 1, 2, 2, 3, self.elapsed)        vbox = gtk.VBox(False, 5)        vbox.pack_start(self.details, False, False)        vbox.pack_start(self.table, False, False)                hbox = gtk.HBox(False, 5)        hbox.pack_start(self.image, False, False)        hbox.pack_start(vbox, True, True)                self.add(hbox)            self.connect('delete-event', self.reset)        self.connect('expose-event', self.on_expose_event)        parentWidget.connect('enter-notify-event', self.on_motion)        parentWidget.connect('leave-notify-event', self.on_leave)        self.tag = None        self.path_array = None    def addLabel(self, s, left, right, top, bottom, label = None):        if label == None:            label = gtk.Label(s)                label.set_alignment(0, 0)        self.table.attach(label, left, right, top, bottom)    def hideTooltip(self):        '''Hides the tooltip and removes any ongoing timeout for the tooltip        to be shown'''                self.hide()        self.reset()        def reset(self):        if self.tag and not self.tag == -1:                gobject.source_remove(self.tag)        self.tag = None        def on_motion(self, view, event):        eventCoords = (event.x_root, event.y_root, int(event.y))        self.tag = gobject.timeout_add(DELAY, self.show_tooltip, \                                            view, eventCoords)    def show_tooltip(self, view, origCoords):        pixbuf = self.transfer.getPreviewImage()                #amsn sends a big. black preview? :S        if pixbuf != None and pixbuf.get_height() <= 96 and pixbuf.get_width() <= 96:            self.image.set_from_pixbuf(pixbuf)        # set the location of the tooltip        x, y = self.computePosition(origCoords, view.window)        self.move(x, y)        self.update()        self.show_all()        return False    def update(self):        self.details.set_markup('<b>' + self.transfer.getFilename() + '</b>')        bps = self.transfer.getAverageSpeed()        seconds = self.transfer.getElapsedTime()        received, total = self.transfer.getBytes()                percentage = int(self.transfer.getFraction() * 100)        self.status.set_text('%d%% (%d/%d KB)' % (percentage,  int(received) / 1024, int(total) / 1024))        self.elapsed.set_text('%.2d:%.2d' % (int(seconds / 60), int(seconds % 60)))        self.speed.set_text('%.2f KiB/s' % (float(bps) / 1024.0))    def on_leave(self, view, event):        self.hide()        self.reset()    # display a border around the tooltip    def on_expose_event(self, tooltip_window, event):        width, height = tooltip_window.get_size()        tooltip_window.style.paint_flat_box(tooltip_window.window, \                                            gtk.STATE_NORMAL, gtk.SHADOW_OUT, \                                            None, tooltip_window, 'tooltip', \                                            0, 0, width, height)            def computePosition(self, origCoords, viewWindow):        x_root, y_root, origY = origCoords        currentY = viewWindow.get_pointer()[1]                width, height = self.get_size()        s_width, s_height = gtk.gdk.screen_width(), gtk.gdk.screen_height()        x = int(x_root) - width/2        if currentY >= origY:            y = int(y_root) + 24        else:            y = int(y_root) + 6        # check if over the screen        if x + width > s_width:            x = s_width - width        elif x < 0:            x = 0        if y + height > s_height:            y = y - height - 24        elif y < 0:            y = 0                    return (x, y)