Show
Ignore:
Timestamp:
08/09/07 17:39:18 (17 months ago)
Author:
asterix
Message:

merge diff from trunk to pep branch

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • branches/pep/src/chat_control.py

    r8197 r8478  
    55## Copyright (C) 2006 Travis Shirk <travis@pobox.com> 
    66## Copyright (C) 2006 Dimitur Kirov <dkirov@gmail.com> 
     7## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net> 
     8## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com> 
    79## 
    810## This program is free software; you can redistribute it and/or modify 
     
    130132                self.handlers[id] = self.widget 
    131133 
     134                # Create banner and connect signals 
    132135                widget = self.xml.get_widget('banner_eventbox') 
     136                widget.set_property('height-request', gajim.config.get('chat_avatar_height')) 
    133137                id = widget.connect('button-press-event', 
    134138                        self._on_banner_eventbox_button_press_event) 
    135139                self.handlers[id] = widget 
     140                # Init DND 
     141                self.TARGET_TYPE_URI_LIST = 80 
     142                self.dnd_list = [ ( 'text/uri-list', 0, self.TARGET_TYPE_URI_LIST ), 
     143                                ('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_APP, 0)] 
     144                id = self.widget.connect('drag_data_received', 
     145                        self._on_drag_data_received) 
     146                self.handlers[id] = self.widget 
     147                self.widget.drag_dest_set(gtk.DEST_DEFAULT_MOTION | 
     148                        gtk.DEST_DEFAULT_HIGHLIGHT | 
     149                        gtk.DEST_DEFAULT_DROP, 
     150                        self.dnd_list, gtk.gdk.ACTION_COPY) 
    136151 
    137152                # Create textviews and connect signals 
    138153                self.conv_textview = ConversationTextview(self.account) 
     154                # FIXME: DND on non editable TextView, find a better way 
     155                self.drag_entered = False 
     156                id = self.conv_textview.tv.connect('drag_data_received', 
     157                        self._on_drag_data_received) 
     158                self.handlers[id] = self.conv_textview.tv 
     159                id = self.conv_textview.tv.connect('drag_motion', self._on_drag_motion) 
     160                self.handlers[id] = self.conv_textview.tv 
     161                id = self.conv_textview.tv.connect('drag_leave', self._on_drag_leave) 
     162                self.handlers[id] = self.conv_textview.tv 
     163                self.conv_textview.tv.drag_dest_set(gtk.DEST_DEFAULT_MOTION | 
     164                        gtk.DEST_DEFAULT_HIGHLIGHT | 
     165                        gtk.DEST_DEFAULT_DROP, 
     166                        self.dnd_list, gtk.gdk.ACTION_COPY) 
    139167 
    140168                self.conv_scrolledwindow = self.xml.get_widget( 
     
    150178                self.scroll_to_end_id = None 
    151179                self.was_at_the_end = True 
     180 
    152181                # add MessageTextView to UI and connect signals 
    153182                self.msg_scrolledwindow = self.xml.get_widget('message_scrolledwindow') 
     
    165194                        self.on_msg_textview_populate_popup) 
    166195                self.handlers[id] = self.msg_textview 
     196                # Setup DND 
     197                id = self.msg_textview.connect('drag_data_received', 
     198                        self._on_drag_data_received) 
     199                self.handlers[id] = self.msg_textview 
     200                self.msg_textview.drag_dest_set(gtk.DEST_DEFAULT_MOTION | 
     201                        gtk.DEST_DEFAULT_HIGHLIGHT, 
     202                        self.dnd_list, gtk.gdk.ACTION_COPY) 
    167203         
    168204                self.update_font() 
     
    482518                                event_keymod) 
    483519 
     520        def _on_drag_data_received(self, widget, context, x, y, selection, 
     521                target_type, timestamp): 
     522                pass  # Derived classes SHOULD implement this method 
     523 
     524        def _on_drag_leave(self, widget, context, time): 
     525                # FIXME: DND on non editable TextView, find a better way 
     526                self.drag_entered = False 
     527                self.conv_textview.tv.set_editable(False) 
     528 
     529        def _on_drag_motion(self, widget, context, x, y, time): 
     530                # FIXME: DND on non editable TextView, find a better way 
     531                if not self.drag_entered: 
     532                        # We drag new data over the TextView, make it editable to catch dnd 
     533                        self.drag_entered_conv = True 
     534                        self.conv_textview.tv.set_editable(True) 
     535 
    484536        def _process_command(self, message): 
    485537                if not message or message[0] != '/': 
     
    497549                        return True 
    498550                elif message == 'compact' and not len(message_array): 
    499                         self.chat_buttons_set_visible(not self.hide_chat_buttons_current) 
     551                        self.chat_buttons_set_visible(not self.hide_chat_buttons) 
    500552                        self.clear(self.msg_textview) 
    501553                        return True 
     
    503555 
    504556        def send_message(self, message, keyID = '', type = 'chat', chatstate = None, 
    505         msg_id = None, composing_jep = None, resource = None): 
     557        msg_id = None, composing_xep = None, resource = None, 
     558        process_command = True): 
    506559                '''Send the given message to the active tab. Doesn't return None if error 
    507560                ''' 
     
    509562                        return 1 
    510563 
    511  
    512                 if not self._process_command(message): 
     564                if not process_command or not self._process_command(message): 
    513565                        ret = MessageControl.send_message(self, message, keyID, type = type, 
    514566                                chatstate = chatstate, msg_id = msg_id, 
    515                                 composing_jep = composing_jep, resource = resource, 
     567                                composing_xep = composing_xep, resource = resource, 
    516568                                user_nick = self.user_nick) 
    517569                        if ret: 
     
    570622                        not self.parent_win.is_active() or not end)) or \ 
    571623                        (gc_message and \ 
    572                         gajim.interface.minimized_controls.has_key(self.account) and \ 
    573624                        jid in gajim.interface.minimized_controls[self.account])) and \ 
    574625                        kind in ('incoming', 'incoming_queue'): 
     
    668719                                history_window.HistoryWindow(jid, self.account) 
    669720 
    670         def _on_compact_view_menuitem_activate(self, widget): 
    671                 isactive = widget.get_active() 
    672                 self.chat_buttons_set_visible(isactive) 
    673  
    674         def _on_minimize_menuitem_activate(self, widget): 
     721        def on_minimize_menuitem_toggled(self, widget): 
    675722                '''When a grouchat is minimized, unparent the tab, put it in roster etc''' 
    676                 win = gajim.interface.msg_win_mgr.get_window(self.contact.jid, self.account) 
    677                 ctrl = win.get_control(self.contact.jid, self.account) 
    678  
    679                 ctrl_page = win.notebook.page_num(ctrl.widget) 
    680                 control = win.notebook.get_nth_page(ctrl_page) 
    681  
    682                 win.notebook.remove_page(ctrl_page) 
    683                 control.unparent() 
    684                 ctrl.parent_win = None 
    685  
    686                 if not gajim.interface.minimized_controls.has_key(self.account): 
    687                         gajim.interface.minimized_controls[self.account] = {} 
    688                 gajim.interface.minimized_controls[self.account][self.contact.jid] = ctrl 
    689  
    690                 del win._controls[self.account][self.contact.jid] 
    691  
    692                 win.check_tabs() 
    693                 gajim.interface.roster.add_groupchat_to_roster(self.account, 
    694                         self.contact.jid, status = self.subject) 
     723                old_value = False 
     724                minimized_gc = gajim.config.get_per('accounts', self.account, 
     725                        'minimized_gc').split() 
     726                if self.contact.jid in minimized_gc: 
     727                        old_value = True 
     728                minimize = widget.get_active() 
     729                if minimize and not self.contact.jid in minimized_gc: 
     730                        minimized_gc.append(self.contact.jid) 
     731                if not minimize and self.contact.jid in minimized_gc: 
     732                        minimized_gc.remove(self.contact.jid) 
     733                if old_value != minimize: 
     734                        gajim.config.set_per('accounts', self.account, 'minimized_gc', 
     735                                ' '.join(minimized_gc)) 
    695736 
    696737        def set_control_active(self, state): 
     
    826867                        groupchat_control = gajim.interface.msg_win_mgr.get_control( 
    827868                                room_jid, self.account) 
    828                         if not groupchat_control and \ 
    829                         gajim.interface.minimized_controls.has_key(self.account) and \ 
    830                         room_jid in gajim.interface.minimized_controls[self.account]: 
     869                        if room_jid in gajim.interface.minimized_controls[self.account]: 
    831870                                groupchat_control = \ 
    832871                                        gajim.interface.minimized_controls[self.account][room_jid] 
     872                        contact = \ 
     873                                gajim.contacts.get_contact_with_highest_priority(self.account, \ 
     874                                room_jid) 
     875                        if contact: 
     876                                gajim.interface.roster.draw_contact(room_jid, self.account) 
    833877                        groupchat_control.draw_contact(nick) 
    834878                        mw = gajim.interface.msg_win_mgr.get_window(room_jid, self.account) 
     
    904948        TYPE_ID = message_control.TYPE_CHAT 
    905949        old_msg_kind = None # last kind of the printed message 
    906         CHAT_CMDS = ['clear', 'compact', 'help', 'ping'] 
     950        CHAT_CMDS = ['clear', 'compact', 'help', 'me', 'ping', 'say'] 
    907951         
    908952        def __init__(self, parent_win, contact, acct, resource = None): 
     
    916960                self.handlers[id] = widget 
    917961 
    918                 hide_chat_buttons_always = gajim.config.get( 
    919                         'always_hide_chat_buttons') 
    920                 self.chat_buttons_set_visible(hide_chat_buttons_always) 
     962                compact_view = gajim.config.get('compact_view') 
     963                self.chat_buttons_set_visible(compact_view) 
    921964                self.widget_set_visible(self.xml.get_widget('banner_eventbox'), 
    922965                        gajim.config.get('hide_chat_banner')) 
    923                 # Initialize drag-n-drop 
    924                 self.TARGET_TYPE_URI_LIST = 80 
    925                 self.dnd_list = [ ( 'text/uri-list', 0, self.TARGET_TYPE_URI_LIST ) ] 
    926                 id = self.widget.connect('drag_data_received', 
    927                         self._on_drag_data_received) 
    928                 self.handlers[id] = self.widget 
    929                 self.widget.drag_dest_set(gtk.DEST_DEFAULT_MOTION | 
    930                         gtk.DEST_DEFAULT_HIGHLIGHT | 
    931                         gtk.DEST_DEFAULT_DROP, 
    932                         self.dnd_list, gtk.gdk.ACTION_COPY) 
    933966 
    934967                # keep timeout id and window obj for possible big avatar 
     
    10861119 
    10871120                banner_name_label = self.xml.get_widget('banner_name_label') 
     1121                banner_eventbox = self.xml.get_widget('banner_eventbox') 
     1122                 
    10881123                name = contact.get_shown_name() 
    10891124                if self.resource: 
     
    11121147                status = contact.status 
    11131148                if status is not None: 
     1149                        self.status_tooltip.set_tip(banner_eventbox, status) 
     1150                        self.status_tooltip.enable() 
    11141151                        banner_name_label.set_ellipsize(pango.ELLIPSIZE_END) 
    1115                         status = helpers.reduce_chars_newlines(status, max_lines = 2) 
     1152                        status = helpers.reduce_chars_newlines(status, max_lines = 1) 
    11161153                status_escaped = gobject.markup_escape_text(status) 
    11171154 
     
    11221159                        if contact.show == 'offline': 
    11231160                                chatstate = '' 
    1124                         elif contact.composing_jep == 'JEP-0085': 
     1161                        elif contact.composing_xep == 'XEP-0085': 
    11251162                                if st == 'all' or cs == 'composing': 
    11261163                                        chatstate = helpers.get_uf_chatstate(cs) 
    11271164                                else: 
    11281165                                        chatstate = '' 
    1129                         elif contact.composing_jep == 'JEP-0022': 
     1166                        elif contact.composing_xep == 'XEP-0022': 
    11301167                                if cs in ('composing', 'paused'): 
    11311168                                        # only print composing, paused 
     
    11461183                        label_text += '\n<span %s>%s</span>' %\ 
    11471184                                (font_attrs_small, status_escaped) 
    1148                         banner_eventbox = self.xml.get_widget('banner_eventbox') 
    1149                         self.status_tooltip.set_tip(banner_eventbox, status) 
    1150                         self.status_tooltip.enable() 
    11511185                else: 
    11521186                        self.status_tooltip.disable() 
     
    11971231                        message_array = [] 
    11981232 
     1233                if command == 'me': 
     1234                        return False # This is not really a command 
     1235 
    11991236                if command == 'help': 
    12001237                        if len(message_array): 
     
    12051242                        self.clear(self.msg_textview) 
    12061243                        return True 
    1207                 elif command == 'ping' and not len(message_array): 
    1208                         gajim.connections[self.account].sendPing(self.contact) 
     1244                elif command == 'ping': 
     1245                        if not len(message_array): 
     1246                                gajim.connections[self.account].sendPing(self.contact) 
     1247                        else: 
     1248                                self.get_command_help(command) 
    12091249                        self.clear(self.msg_textview) 
     1250                        return True 
     1251                elif command == 'say': 
     1252                        return False 
     1253                else: 
     1254                        self.print_conversation(_('No such command: /%s (if you want to send ' 
     1255                                'this, prefix it with /say)') % command, 'info') 
    12101256                        return True 
    12111257                return False 
     
    12161262                                'info') 
    12171263                elif command == 'clear': 
    1218                         self.print_conversation(_('Usage: /%s, clears the text window.'), 
    1219                                 'info') 
     1264                        self.print_conversation(_('Usage: /%s, clears the text window.') % \ 
     1265                                command, 'info') 
    12201266                elif command == 'compact': 
    1221                         self.print_conversation(_('Usage: /%s, hide the chat buttons.'), 
    1222                                 'info') 
     1267                        self.print_conversation(_('Usage: /%s, hide the chat buttons.') % \ 
     1268                                command, 'info') 
     1269                elif command == 'me': 
     1270                        self.print_conversation(_('Usage: /%s <action>, sends action to the ' 
     1271                                'current group chat. Use third person. (e.g. /%s explodes.)') % \ 
     1272                                (command, command), 'info') 
    12231273                elif command == 'ping': 
    1224                         self.print_conversation(_(''), 'info') 
     1274                        self.print_conversation(_('Usage: /%s, sends a ping to the contact') %\ 
     1275                                command, 'info') 
     1276                elif command == 'say': 
     1277                        self.print_conversation(_('Usage: /%s, send the message to the contact') %\ 
     1278                                command, 'info') 
    12251279                else: 
    12261280                        self.print_conversation(_('No help info for /%s') % command, 'info') 
     
    12301284                if message in ('', None, '\n') or self._process_command(message): 
    12311285                        return 
     1286 
     1287                # Do we need to process command for the message ? 
     1288                process_command = True 
     1289                if message.startswith('/say'): 
     1290                        message = message[5:] 
     1291                        process_command = False 
    12321292 
    12331293                # refresh timers 
     
    12451305                chatstates_on = gajim.config.get('outgoing_chat_state_notifications') != \ 
    12461306                        'disabled' 
    1247                 composing_jep = contact.composing_jep 
     1307                composing_xep = contact.composing_xep 
    12481308                chatstate_to_send = None 
    12491309                if chatstates_on and contact is not None: 
    1250                         if composing_jep is None: 
     1310                        if composing_xep is None: 
    12511311                                # no info about peer 
    12521312                                # send active to discover chat state capabilities 
     
    12571317                                if contact.our_chatstate: 
    12581318                                        # We already asked for xep 85, don't ask it twice 
    1259                                         composing_jep = 'asked_once' 
     1319                                        composing_xep = 'asked_once' 
    12601320 
    12611321                                chatstate_to_send = 'active' 
     
    12631323                        # if peer supports jep85 and we are not 'ask', send 'active' 
    12641324                        # NOTE: first active and 'ask' is set in gajim.py 
    1265                         elif composing_jep is not False: 
     1325                        elif composing_xep is not False: 
    12661326                                #send active chatstate on every message (as JEP says) 
    12671327                                chatstate_to_send = 'active' 
     
    12731333                                 
    12741334                if not ChatControlBase.send_message(self, message, keyID, type = 'chat', 
    1275                 chatstate = chatstate_to_send, composing_jep = composing_jep): 
     1335                chatstate = chatstate_to_send, composing_xep = composing_xep, 
     1336                process_command = process_command): 
    12761337                        self.print_conversation(message, self.contact.jid, 
    12771338                                encrypted = encrypted) 
     
    14421503                num_unread = len(gajim.events.get_events(self.account, jid, 
    14431504                        ['printed_' + self.type_id, self.type_id])) 
    1444                 # Set tab image (always 16x16); unread messages show the 'message' image 
     1505                # Set tab image (always 16x16); unread messages show the 'event' image 
    14451506                tab_img = None 
    14461507                 
    14471508                if num_unread and gajim.config.get('show_unread_tab_icon'): 
    14481509                        img_16 = gajim.interface.roster.get_appropriate_state_images( 
    1449                                 self.contact.jid, icon_name = 'message') 
    1450                         tab_img = img_16['message'] 
     1510                                self.contact.jid, icon_name = 'event') 
     1511                        tab_img = img_16['event'] 
    14511512                else: 
    14521513                        contact = gajim.contacts.get_contact_with_highest_priority( 
     
    14751536                add_to_roster_menuitem = xml.get_widget('add_to_roster_menuitem') 
    14761537                send_file_menuitem = xml.get_widget('send_file_menuitem') 
    1477                 compact_view_menuitem = xml.get_widget('compact_view_menuitem') 
    14781538                information_menuitem = xml.get_widget('information_menuitem') 
    14791539                 
     
    14941554                # If we don't have resource, we can't do file transfer 
    14951555                # in transports, contact holds our info we need to disable it too 
    1496                 if contact.resource and contact.jid.find('@') != -1: 
     1556                if self.TYPE_ID == message_control.TYPE_PM and self.gc_contact.jid and \ 
     1557                self.gc_contact.resource: 
    14971558                        send_file_menuitem.set_sensitive(True) 
     1559                elif contact.resource and contact.jid.find('@') != -1: 
     1560                        send_file_menuitem.set_sensitive(True) 
    14981561                else: 
    14991562                        send_file_menuitem.set_sensitive(False) 
    1500                  
    1501                 # compact_view_menuitem 
    1502                 compact_view_menuitem.set_active(self.hide_chat_buttons_current) 
    15031563                 
    15041564                # add_to_roster_menuitem 
     
    15181578                        self._on_send_file_menuitem_activate) 
    15191579                self.handlers[id] = send_file_menuitem  
    1520                 id = compact_view_menuitem.connect('activate',  
    1521                         self._on_compact_view_menuitem_activate) 
    1522                 self.handlers[id] = compact_view_menuitem  
    15231580                id = add_to_roster_menuitem.connect('activate',  
    15241581                        self._on_add_to_roster_menuitem_activate) 
     
    15661623                        return 
    15671624 
    1568                 if contact.composing_jep is False: # jid cannot do jep85 nor jep22 
     1625                if contact.composing_xep is False: # jid cannot do xep85 nor xep22 
    15691626                        return 
    15701627 
     
    15741631                        return 
    15751632 
    1576                 if contact.composing_jep is None: 
     1633                if contact.composing_xep is None: 
    15771634                        # we don't know anything about jid, so return 
    15781635                        # NOTE: 
     
    15881645                # in JEP22, when we already sent stop composing 
    15891646                # notification on paused, don't resend it 
    1590                 if contact.composing_jep == 'JEP-0022' and \ 
     1647                if contact.composing_xep == 'XEP-0022' and \ 
    15911648                contact.our_chatstate in ('paused', 'active', 'inactive') and \ 
    15921649                state is not 'composing': # not composing == in (active, inactive, gone) 
     
    16101667 
    16111668                MessageControl.send_message(self, None, chatstate = state, 
    1612                         msg_id = contact.msg_id, composing_jep = contact.composing_jep) 
     1669                        msg_id = contact.msg_id, composing_xep = contact.composing_xep) 
    16131670                contact.our_chatstate = state 
    16141671                if contact.our_chatstate == 'active': 
     
    16391696                self.conv_textview.del_handlers() 
    16401697                self.msg_textview.destroy() 
    1641                  
    16421698 
    16431699        def allow_shutdown(self, method): 
     
    16461702                        # 2 seconds 
    16471703                        dialog = dialogs.ConfirmationDialog( 
    1648                                 #%s is being replaced in the code with JID 
     1704                                # %s is being replaced in the code with JID 
    16491705                                _('You just received a new message from "%s"') % self.contact.jid, 
    16501706                                _('If you close this tab and you have history disabled, '\ 
    16511707                                'this message will be lost.')) 
    16521708                        if dialog.get_response() != gtk.RESPONSE_OK: 
    1653                                 return False #stop the propagation of the event 
    1654                 return True 
     1709                                return 'no' # stop the propagation of the event 
     1710                return 'yes' 
    16551711 
    16561712        def handle_incoming_chatstate(self): 
     
    17111767        def _on_drag_data_received(self, widget, context, x, y, selection, 
    17121768                target_type, timestamp): 
    1713                 # If not resource, we can't send file 
    1714                 if not self.contact.resource: 
     1769                # If no resource is known, we can't send a file 
     1770                if self.TYPE_ID == message_control.TYPE_PM: 
     1771                        c = self.gc_contact 
     1772                else: 
     1773                        c = self.contact 
     1774                if not c.resource: 
    17151775                        return 
    17161776                if target_type == self.TARGET_TYPE_URI_LIST: 
     1777                        if not selection.data: 
     1778                                return 
    17171779                        uri = selection.data.strip() 
    17181780                        uri_splitted = uri.split() # we may have more than one file dropped 
     
    17211783                                if os.path.isfile(path): # is it file? 
    17221784                                        ft = gajim.interface.instances['file_transfers'] 
    1723                                         ft.send_file(self.account, self.contact, path) 
     1785                                        ft.send_file(self.account, c, path) 
    17241786 
    17251787        def _on_message_tv_buffer_changed(self, textbuffer): 
     
    18341896                        if (not show_transports and gajim.jid_is_transport(jid)) or \ 
    18351897                        (not show_offline and typ == 'chat' and \ 
    1836                         len(gajim.contacts.get_contact(self.account, jid)) < 2): 
     1898                        len(gajim.contacts.get_contacts(self.account, jid)) < 2): 
    18371899                                gajim.interface.roster.really_remove_contact(self.contact, 
    18381900                                        self.account) 
     
    19201982 
    19211983        def _on_send_file_menuitem_activate(self, widget): 
     1984                if self.TYPE_ID == message_control.TYPE_PM: 
     1985                        c = self.gc_contact 
     1986                else: 
     1987                        c = self.contact 
    19221988                gajim.interface.instances['file_transfers'].show_file_send_request(  
    1923                         self.account, self.contact) 
     1989                        self.account, c) 
    19241990 
    19251991        def _on_add_to_roster_menuitem_activate(self, widget):