| 1 | ## plugins/tabbed_chat_window.py |
|---|
| 2 | ## |
|---|
| 3 | ## Gajim Team: |
|---|
| 4 | ## - Yann Le Boulanger <asterix@lagaule.org> |
|---|
| 5 | ## - Vincent Hanquez <tab@snarc.org> |
|---|
| 6 | ## - Nikos Kouremenos <kourem@gmail.com> |
|---|
| 7 | ## |
|---|
| 8 | ## Copyright (C) 2003-2005 Gajim Team |
|---|
| 9 | ## |
|---|
| 10 | ## This program is free software; you can redistribute it and/or modify |
|---|
| 11 | ## it under the terms of the GNU General Public License as published |
|---|
| 12 | ## by the Free Software Foundation; version 2 only. |
|---|
| 13 | ## |
|---|
| 14 | ## This program is distributed in the hope that it will be useful, |
|---|
| 15 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 16 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 17 | ## GNU General Public License for more details. |
|---|
| 18 | ## |
|---|
| 19 | |
|---|
| 20 | import gtk |
|---|
| 21 | import gtk.glade |
|---|
| 22 | import pango |
|---|
| 23 | import gobject |
|---|
| 24 | import time |
|---|
| 25 | |
|---|
| 26 | from dialogs import * |
|---|
| 27 | from history_window import * |
|---|
| 28 | from chat import * |
|---|
| 29 | |
|---|
| 30 | from common import i18n |
|---|
| 31 | |
|---|
| 32 | _ = i18n._ |
|---|
| 33 | APP = i18n.APP |
|---|
| 34 | gtk.glade.bindtextdomain(APP, i18n.DIR) |
|---|
| 35 | gtk.glade.textdomain(APP) |
|---|
| 36 | |
|---|
| 37 | GTKGUI_GLADE='plugins/gtkgui/gtkgui.glade' |
|---|
| 38 | |
|---|
| 39 | class Tabbed_chat_window(Chat): |
|---|
| 40 | """Class for tabbed chat window""" |
|---|
| 41 | def __init__(self, user, plugin, account): |
|---|
| 42 | Chat.__init__(self, plugin, account, 'tabbed_chat_window') |
|---|
| 43 | self.users = {} |
|---|
| 44 | self.new_user(user) |
|---|
| 45 | self.show_title() |
|---|
| 46 | self.xml.signal_connect('on_tabbed_chat_window_destroy', \ |
|---|
| 47 | self.on_tabbed_chat_window_destroy) |
|---|
| 48 | self.xml.signal_connect('on_tabbed_chat_window_delete_event', \ |
|---|
| 49 | self.on_tabbed_chat_window_delete_event) |
|---|
| 50 | self.xml.signal_connect('on_tabbed_chat_window_focus_in_event', \ |
|---|
| 51 | self.on_tabbed_chat_window_focus_in_event) |
|---|
| 52 | self.xml.signal_connect('on_chat_notebook_key_press_event', \ |
|---|
| 53 | self.on_chat_notebook_key_press_event) |
|---|
| 54 | self.xml.signal_connect('on_chat_notebook_switch_page', \ |
|---|
| 55 | self.on_chat_notebook_switch_page) |
|---|
| 56 | |
|---|
| 57 | def draw_widgets(self, user): |
|---|
| 58 | """draw the widgets in a tab (status_image, contact_button ...) |
|---|
| 59 | according to the the information in the user variable""" |
|---|
| 60 | jid = user.jid |
|---|
| 61 | status_image = self.xmls[jid].get_widget('status_image') |
|---|
| 62 | image = self.plugin.roster.pixbufs[user.show] |
|---|
| 63 | if image.get_storage_type() == gtk.IMAGE_ANIMATION: |
|---|
| 64 | status_image.set_from_animation(image.get_animation()) |
|---|
| 65 | elif image.get_storage_type() == gtk.IMAGE_PIXBUF: |
|---|
| 66 | status_image.set_from_pixbuf(image.get_pixbuf()) |
|---|
| 67 | contact_button = self.xmls[jid].get_widget('contact_button') |
|---|
| 68 | contact_button.set_label(user.name + ' <' + jid + '>') |
|---|
| 69 | if not user.keyID: |
|---|
| 70 | self.xmls[jid].get_widget('gpg_togglebutton').set_sensitive(False) |
|---|
| 71 | |
|---|
| 72 | def set_image(self, jid): |
|---|
| 73 | prio = 0 |
|---|
| 74 | list_users = self.plugin.roster.contacts[self.account][jid] |
|---|
| 75 | sho = list_users[0].show |
|---|
| 76 | for u in list_users: |
|---|
| 77 | if u.priority > prio: |
|---|
| 78 | prio = u.priority |
|---|
| 79 | sho = u.show |
|---|
| 80 | image = self.plugin.roster.pixbufs[sho] |
|---|
| 81 | if image.get_storage_type() == gtk.IMAGE_ANIMATION: |
|---|
| 82 | self.xmls[jid].get_widget('status_image').\ |
|---|
| 83 | set_from_animation(image.get_animation()) |
|---|
| 84 | elif image.get_storage_type() == gtk.IMAGE_PIXBUF: |
|---|
| 85 | self.xmls[jid].get_widget('status_image').\ |
|---|
| 86 | set_from_pixbuf(image.get_pixbuf()) |
|---|
| 87 | |
|---|
| 88 | def on_tabbed_chat_window_delete_event(self, widget, event): |
|---|
| 89 | """close window""" |
|---|
| 90 | for jid in self.users: |
|---|
| 91 | if time.time() - self.last_message_time[jid] < 2: # 2 seconds |
|---|
| 92 | dialog = Confirmation_dialog(_('You received a message from %s in the last two seconds.\nDo you still want to close this window ?') % jid) |
|---|
| 93 | if dialog.get_response() != gtk.RESPONSE_YES: |
|---|
| 94 | return True #stop the propagation of the event |
|---|
| 95 | |
|---|
| 96 | def on_tabbed_chat_window_destroy(self, widget): |
|---|
| 97 | #clean self.plugin.windows[self.account]['chats'] |
|---|
| 98 | Chat.on_window_destroy(self, widget, 'chats') |
|---|
| 99 | |
|---|
| 100 | def on_tabbed_chat_window_focus_in_event(self, widget, event): |
|---|
| 101 | Chat.on_chat_window_focus_in_event(self, widget, event) |
|---|
| 102 | |
|---|
| 103 | def on_chat_notebook_key_press_event(self, widget, event): |
|---|
| 104 | Chat.on_chat_notebook_key_press_event(self, widget, event) |
|---|
| 105 | |
|---|
| 106 | def on_clear_button_clicked(self, widget): |
|---|
| 107 | """When clear button is pressed : |
|---|
| 108 | clear the conversation""" |
|---|
| 109 | jid = self.get_active_jid() |
|---|
| 110 | conversation_buffer = self.xmls[jid].get_widget('conversation_textview').\ |
|---|
| 111 | get_buffer() |
|---|
| 112 | start, end = conversation_buffer.get_bounds() |
|---|
| 113 | conversation_buffer.delete(start, end) |
|---|
| 114 | |
|---|
| 115 | def on_history_button_clicked(self, widget): |
|---|
| 116 | """When history button is pressed : call history window""" |
|---|
| 117 | jid = self.get_active_jid() |
|---|
| 118 | if not self.plugin.windows['logs'].has_key(jid): |
|---|
| 119 | self.plugin.windows['logs'][jid] = history_window(self.plugin, jid) |
|---|
| 120 | |
|---|
| 121 | def remove_tab(self, jid): |
|---|
| 122 | if time.time() - self.last_message_time[jid] < 2: |
|---|
| 123 | dialog = Confirmation_dialog(_('You received a message from %s in the last two seconds.\nDo you still want to close this tab?') % jid) |
|---|
| 124 | if dialog.get_response() != gtk.RESPONSE_YES: |
|---|
| 125 | return |
|---|
| 126 | |
|---|
| 127 | Chat.remove_tab(self, jid, 'chats') |
|---|
| 128 | if len(self.xmls) > 0: |
|---|
| 129 | del self.users[jid] |
|---|
| 130 | |
|---|
| 131 | def new_user(self, user): |
|---|
| 132 | self.names[user.jid] = user.name |
|---|
| 133 | self.xmls[user.jid] = gtk.glade.XML(GTKGUI_GLADE, 'chats_vbox', APP) |
|---|
| 134 | self.childs[user.jid] = self.xmls[user.jid].get_widget('chats_vbox') |
|---|
| 135 | Chat.new_tab(self, user.jid) |
|---|
| 136 | self.users[user.jid] = user |
|---|
| 137 | |
|---|
| 138 | self.redraw_tab(user.jid) |
|---|
| 139 | self.draw_widgets(user) |
|---|
| 140 | |
|---|
| 141 | #print queued messages |
|---|
| 142 | if self.plugin.queues[self.account].has_key(user.jid): |
|---|
| 143 | self.read_queue(user.jid) |
|---|
| 144 | if user.show != 'online': |
|---|
| 145 | self.print_conversation(_("%s is now %s (%s)") % (user.name, \ |
|---|
| 146 | user.show, user.status), user.jid, 'status') |
|---|
| 147 | |
|---|
| 148 | if self.plugin.config['print_time'] == 'sometimes': |
|---|
| 149 | self.print_time_timeout(user.jid) |
|---|
| 150 | self.print_time_timeout_id[user.jid] = gobject.timeout_add(300000, \ |
|---|
| 151 | self.print_time_timeout, user.jid) |
|---|
| 152 | |
|---|
| 153 | def on_message_textview_key_press_event(self, widget, event): |
|---|
| 154 | """When a key is pressed : |
|---|
| 155 | if enter is pressed without the shit key, message (if not empty) is sent |
|---|
| 156 | and printed in the conversation""" |
|---|
| 157 | jid = self.get_active_jid() |
|---|
| 158 | conversation_textview = self.xmls[jid].get_widget('conversation_textview') |
|---|
| 159 | if event.keyval == gtk.keysyms.Tab and \ |
|---|
| 160 | (event.state & gtk.gdk.CONTROL_MASK): # CTRL + TAB |
|---|
| 161 | self.notebook.emit('key_press_event', event) |
|---|
| 162 | elif event.keyval == gtk.keysyms.Page_Down: # PAGE DOWN |
|---|
| 163 | if event.state & gtk.gdk.CONTROL_MASK: # CTRL + PAGE DOWN |
|---|
| 164 | self.notebook.emit('key_press_event', event) |
|---|
| 165 | elif event.state & gtk.gdk.SHIFT_MASK: # SHIFT + PAGE DOWN |
|---|
| 166 | conversation_textview.emit('key_press_event', event) |
|---|
| 167 | elif event.keyval == gtk.keysyms.Page_Up: # PAGE UP |
|---|
| 168 | if event.state & gtk.gdk.CONTROL_MASK: # CTRL + PAGE UP |
|---|
| 169 | self.notebook.emit('key_press_event', event) |
|---|
| 170 | elif event.state & gtk.gdk.SHIFT_MASK: # SHIFT + PAGE UP |
|---|
| 171 | conversation_textview.emit('key_press_event', event) |
|---|
| 172 | elif event.keyval == gtk.keysyms.Return or \ |
|---|
| 173 | event.keyval == gtk.keysyms.KP_Enter: # ENTER |
|---|
| 174 | if (event.state & gtk.gdk.SHIFT_MASK): |
|---|
| 175 | return False |
|---|
| 176 | if self.plugin.connected[self.account] < 2: #we are not connected |
|---|
| 177 | Error_dialog(_('You are not connected, so you cannot send a message')) |
|---|
| 178 | return True |
|---|
| 179 | message_buffer = widget.get_buffer() |
|---|
| 180 | start_iter = message_buffer.get_start_iter() |
|---|
| 181 | end_iter = message_buffer.get_end_iter() |
|---|
| 182 | message = message_buffer.get_text(start_iter, end_iter, 0) |
|---|
| 183 | if message != '': |
|---|
| 184 | keyID = '' |
|---|
| 185 | if self.xmls[jid].get_widget('gpg_togglebutton').get_active(): |
|---|
| 186 | keyID = self.users[jid].keyID |
|---|
| 187 | self.plugin.send('MSG', self.account, (jid, message, keyID)) |
|---|
| 188 | message_buffer.set_text('', -1) |
|---|
| 189 | self.print_conversation(message, jid, jid) |
|---|
| 190 | return True |
|---|
| 191 | return False |
|---|
| 192 | |
|---|
| 193 | def on_contact_button_clicked(self, widget): |
|---|
| 194 | """When button contact is clicked""" |
|---|
| 195 | jid = self.get_active_jid() |
|---|
| 196 | user = self.users[jid] |
|---|
| 197 | self.plugin.roster.on_info(widget, user, self.account) |
|---|
| 198 | |
|---|
| 199 | def read_queue(self, jid): |
|---|
| 200 | """read queue and print messages containted in it""" |
|---|
| 201 | q = self.plugin.queues[self.account][jid] |
|---|
| 202 | user = self.users[jid] |
|---|
| 203 | while not q.empty(): |
|---|
| 204 | event = q.get() |
|---|
| 205 | self.print_conversation(event[0], jid, tim = event[1]) |
|---|
| 206 | self.plugin.roster.nb_unread -= 1 |
|---|
| 207 | self.plugin.roster.show_title() |
|---|
| 208 | del self.plugin.queues[self.account][jid] |
|---|
| 209 | self.plugin.roster.redraw_jid(jid, self.account) |
|---|
| 210 | if self.plugin.systray_enabled: |
|---|
| 211 | self.plugin.systray.remove_jid(jid, self.account) |
|---|
| 212 | showOffline = self.plugin.config['showoffline'] |
|---|
| 213 | if (user.show == 'offline' or user.show == 'error') and \ |
|---|
| 214 | not showOffline: |
|---|
| 215 | if len(self.plugin.roster.contacts[self.account][jid]) == 1: |
|---|
| 216 | self.plugin.roster.remove_user(user, self.account) |
|---|
| 217 | |
|---|
| 218 | def print_conversation(self, text, jid, contact = '', tim = None): |
|---|
| 219 | """Print a line in the conversation : |
|---|
| 220 | if contact is set to status : it's a status message |
|---|
| 221 | if contact is set to another value : it's an outgoing message |
|---|
| 222 | if contact is not set : it's an incomming message""" |
|---|
| 223 | user = self.users[jid] |
|---|
| 224 | if contact == 'status': |
|---|
| 225 | kind = 'status' |
|---|
| 226 | name = '' |
|---|
| 227 | else: |
|---|
| 228 | if contact: |
|---|
| 229 | kind = 'outgoing' |
|---|
| 230 | name = self.plugin.nicks[self.account] |
|---|
| 231 | else: |
|---|
| 232 | kind = 'incoming' |
|---|
| 233 | name = user.name |
|---|
| 234 | |
|---|
| 235 | Chat.print_conversation_line(self, text, jid, kind, name, tim) |
|---|