Changeset 8478 for branches/pep/src/chat_control.py
- Timestamp:
- 08/09/07 17:39:18 (17 months ago)
- Files:
-
- 1 modified
-
branches/pep/src/chat_control.py (modified) (39 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/pep/src/chat_control.py
r8197 r8478 5 5 ## Copyright (C) 2006 Travis Shirk <travis@pobox.com> 6 6 ## 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> 7 9 ## 8 10 ## This program is free software; you can redistribute it and/or modify … … 130 132 self.handlers[id] = self.widget 131 133 134 # Create banner and connect signals 132 135 widget = self.xml.get_widget('banner_eventbox') 136 widget.set_property('height-request', gajim.config.get('chat_avatar_height')) 133 137 id = widget.connect('button-press-event', 134 138 self._on_banner_eventbox_button_press_event) 135 139 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) 136 151 137 152 # Create textviews and connect signals 138 153 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) 139 167 140 168 self.conv_scrolledwindow = self.xml.get_widget( … … 150 178 self.scroll_to_end_id = None 151 179 self.was_at_the_end = True 180 152 181 # add MessageTextView to UI and connect signals 153 182 self.msg_scrolledwindow = self.xml.get_widget('message_scrolledwindow') … … 165 194 self.on_msg_textview_populate_popup) 166 195 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) 167 203 168 204 self.update_font() … … 482 518 event_keymod) 483 519 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 484 536 def _process_command(self, message): 485 537 if not message or message[0] != '/': … … 497 549 return True 498 550 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) 500 552 self.clear(self.msg_textview) 501 553 return True … … 503 555 504 556 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): 506 559 '''Send the given message to the active tab. Doesn't return None if error 507 560 ''' … … 509 562 return 1 510 563 511 512 if not self._process_command(message): 564 if not process_command or not self._process_command(message): 513 565 ret = MessageControl.send_message(self, message, keyID, type = type, 514 566 chatstate = chatstate, msg_id = msg_id, 515 composing_ jep = composing_jep, resource = resource,567 composing_xep = composing_xep, resource = resource, 516 568 user_nick = self.user_nick) 517 569 if ret: … … 570 622 not self.parent_win.is_active() or not end)) or \ 571 623 (gc_message and \ 572 gajim.interface.minimized_controls.has_key(self.account) and \573 624 jid in gajim.interface.minimized_controls[self.account])) and \ 574 625 kind in ('incoming', 'incoming_queue'): … … 668 719 history_window.HistoryWindow(jid, self.account) 669 720 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): 675 722 '''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)) 695 736 696 737 def set_control_active(self, state): … … 826 867 groupchat_control = gajim.interface.msg_win_mgr.get_control( 827 868 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]: 831 870 groupchat_control = \ 832 871 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) 833 877 groupchat_control.draw_contact(nick) 834 878 mw = gajim.interface.msg_win_mgr.get_window(room_jid, self.account) … … 904 948 TYPE_ID = message_control.TYPE_CHAT 905 949 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'] 907 951 908 952 def __init__(self, parent_win, contact, acct, resource = None): … … 916 960 self.handlers[id] = widget 917 961 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) 921 964 self.widget_set_visible(self.xml.get_widget('banner_eventbox'), 922 965 gajim.config.get('hide_chat_banner')) 923 # Initialize drag-n-drop924 self.TARGET_TYPE_URI_LIST = 80925 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.widget929 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)933 966 934 967 # keep timeout id and window obj for possible big avatar … … 1086 1119 1087 1120 banner_name_label = self.xml.get_widget('banner_name_label') 1121 banner_eventbox = self.xml.get_widget('banner_eventbox') 1122 1088 1123 name = contact.get_shown_name() 1089 1124 if self.resource: … … 1112 1147 status = contact.status 1113 1148 if status is not None: 1149 self.status_tooltip.set_tip(banner_eventbox, status) 1150 self.status_tooltip.enable() 1114 1151 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) 1116 1153 status_escaped = gobject.markup_escape_text(status) 1117 1154 … … 1122 1159 if contact.show == 'offline': 1123 1160 chatstate = '' 1124 elif contact.composing_ jep == 'JEP-0085':1161 elif contact.composing_xep == 'XEP-0085': 1125 1162 if st == 'all' or cs == 'composing': 1126 1163 chatstate = helpers.get_uf_chatstate(cs) 1127 1164 else: 1128 1165 chatstate = '' 1129 elif contact.composing_ jep == 'JEP-0022':1166 elif contact.composing_xep == 'XEP-0022': 1130 1167 if cs in ('composing', 'paused'): 1131 1168 # only print composing, paused … … 1146 1183 label_text += '\n<span %s>%s</span>' %\ 1147 1184 (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()1151 1185 else: 1152 1186 self.status_tooltip.disable() … … 1197 1231 message_array = [] 1198 1232 1233 if command == 'me': 1234 return False # This is not really a command 1235 1199 1236 if command == 'help': 1200 1237 if len(message_array): … … 1205 1242 self.clear(self.msg_textview) 1206 1243 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) 1209 1249 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') 1210 1256 return True 1211 1257 return False … … 1216 1262 'info') 1217 1263 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') 1220 1266 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') 1223 1273 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') 1225 1279 else: 1226 1280 self.print_conversation(_('No help info for /%s') % command, 'info') … … 1230 1284 if message in ('', None, '\n') or self._process_command(message): 1231 1285 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 1232 1292 1233 1293 # refresh timers … … 1245 1305 chatstates_on = gajim.config.get('outgoing_chat_state_notifications') != \ 1246 1306 'disabled' 1247 composing_ jep = contact.composing_jep1307 composing_xep = contact.composing_xep 1248 1308 chatstate_to_send = None 1249 1309 if chatstates_on and contact is not None: 1250 if composing_ jep is None:1310 if composing_xep is None: 1251 1311 # no info about peer 1252 1312 # send active to discover chat state capabilities … … 1257 1317 if contact.our_chatstate: 1258 1318 # We already asked for xep 85, don't ask it twice 1259 composing_ jep = 'asked_once'1319 composing_xep = 'asked_once' 1260 1320 1261 1321 chatstate_to_send = 'active' … … 1263 1323 # if peer supports jep85 and we are not 'ask', send 'active' 1264 1324 # NOTE: first active and 'ask' is set in gajim.py 1265 elif composing_ jep is not False:1325 elif composing_xep is not False: 1266 1326 #send active chatstate on every message (as JEP says) 1267 1327 chatstate_to_send = 'active' … … 1273 1333 1274 1334 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): 1276 1337 self.print_conversation(message, self.contact.jid, 1277 1338 encrypted = encrypted) … … 1442 1503 num_unread = len(gajim.events.get_events(self.account, jid, 1443 1504 ['printed_' + self.type_id, self.type_id])) 1444 # Set tab image (always 16x16); unread messages show the ' message' image1505 # Set tab image (always 16x16); unread messages show the 'event' image 1445 1506 tab_img = None 1446 1507 1447 1508 if num_unread and gajim.config.get('show_unread_tab_icon'): 1448 1509 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'] 1451 1512 else: 1452 1513 contact = gajim.contacts.get_contact_with_highest_priority( … … 1475 1536 add_to_roster_menuitem = xml.get_widget('add_to_roster_menuitem') 1476 1537 send_file_menuitem = xml.get_widget('send_file_menuitem') 1477 compact_view_menuitem = xml.get_widget('compact_view_menuitem')1478 1538 information_menuitem = xml.get_widget('information_menuitem') 1479 1539 … … 1494 1554 # If we don't have resource, we can't do file transfer 1495 1555 # 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: 1497 1558 send_file_menuitem.set_sensitive(True) 1559 elif contact.resource and contact.jid.find('@') != -1: 1560 send_file_menuitem.set_sensitive(True) 1498 1561 else: 1499 1562 send_file_menuitem.set_sensitive(False) 1500 1501 # compact_view_menuitem1502 compact_view_menuitem.set_active(self.hide_chat_buttons_current)1503 1563 1504 1564 # add_to_roster_menuitem … … 1518 1578 self._on_send_file_menuitem_activate) 1519 1579 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_menuitem1523 1580 id = add_to_roster_menuitem.connect('activate', 1524 1581 self._on_add_to_roster_menuitem_activate) … … 1566 1623 return 1567 1624 1568 if contact.composing_ jep is False: # jid cannot do jep85 nor jep221625 if contact.composing_xep is False: # jid cannot do xep85 nor xep22 1569 1626 return 1570 1627 … … 1574 1631 return 1575 1632 1576 if contact.composing_ jep is None:1633 if contact.composing_xep is None: 1577 1634 # we don't know anything about jid, so return 1578 1635 # NOTE: … … 1588 1645 # in JEP22, when we already sent stop composing 1589 1646 # notification on paused, don't resend it 1590 if contact.composing_ jep == 'JEP-0022' and \1647 if contact.composing_xep == 'XEP-0022' and \ 1591 1648 contact.our_chatstate in ('paused', 'active', 'inactive') and \ 1592 1649 state is not 'composing': # not composing == in (active, inactive, gone) … … 1610 1667 1611 1668 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) 1613 1670 contact.our_chatstate = state 1614 1671 if contact.our_chatstate == 'active': … … 1639 1696 self.conv_textview.del_handlers() 1640 1697 self.msg_textview.destroy() 1641 1642 1698 1643 1699 def allow_shutdown(self, method): … … 1646 1702 # 2 seconds 1647 1703 dialog = dialogs.ConfirmationDialog( 1648 # %s is being replaced in the code with JID1704 # %s is being replaced in the code with JID 1649 1705 _('You just received a new message from "%s"') % self.contact.jid, 1650 1706 _('If you close this tab and you have history disabled, '\ 1651 1707 'this message will be lost.')) 1652 1708 if dialog.get_response() != gtk.RESPONSE_OK: 1653 return False #stop the propagation of the event1654 return True1709 return 'no' # stop the propagation of the event 1710 return 'yes' 1655 1711 1656 1712 def handle_incoming_chatstate(self): … … 1711 1767 def _on_drag_data_received(self, widget, context, x, y, selection, 1712 1768 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: 1715 1775 return 1716 1776 if target_type == self.TARGET_TYPE_URI_LIST: 1777 if not selection.data: 1778 return 1717 1779 uri = selection.data.strip() 1718 1780 uri_splitted = uri.split() # we may have more than one file dropped … … 1721 1783 if os.path.isfile(path): # is it file? 1722 1784 ft = gajim.interface.instances['file_transfers'] 1723 ft.send_file(self.account, self.contact, path)1785 ft.send_file(self.account, c, path) 1724 1786 1725 1787 def _on_message_tv_buffer_changed(self, textbuffer): … … 1834 1896 if (not show_transports and gajim.jid_is_transport(jid)) or \ 1835 1897 (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): 1837 1899 gajim.interface.roster.really_remove_contact(self.contact, 1838 1900 self.account) … … 1920 1982 1921 1983 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 1922 1988 gajim.interface.instances['file_transfers'].show_file_send_request( 1923 self.account, self.contact)1989 self.account, c) 1924 1990 1925 1991 def _on_add_to_roster_menuitem_activate(self, widget):
