Window/control shutdown

This commit is contained in:
Travis Shirk 2006-01-01 19:40:05 +00:00
parent c30ee542dc
commit 6036368b6e
4 changed files with 165 additions and 22 deletions

View File

@ -14,12 +14,14 @@
import os, os.path
import math
import time
import gtk
import gtk.glade
import pango
import gobject
import gtkgui_helpers
import message_window
import dialogs
from common import gajim
from common import helpers
@ -289,8 +291,7 @@ class ChatControlBase(MessageControl):
self.nb_unread += 1
if gajim.interface.systray_enabled and\
gajim.config.get('trayicon_notification_on_new_messages'):
gajim.interface.systray.add_jid(jid, self.account,
self.get_message_type(jid))
gajim.interface.systray.add_jid(jid, self.account, self.type)
self.redraw_tab(jid)
self.show_title(urgent)
@ -395,11 +396,11 @@ class ChatControlBase(MessageControl):
################################################################################
class ChatControl(ChatControlBase):
'''A control for standard 1-1 chat'''
TYPE_ID = 1
TYPE_ID = 'chat'
def __init__(self, parent_win, contact, acct):
ChatControlBase.__init__(self, self.TYPE_ID, parent_win, 'chat_child_vbox',
_('Chat'), contact, acct);
_('Chat'), contact, acct)
self.compact_view_always = gajim.config.get('always_compact_view_chat')
self.set_compact_view(self.compact_view_always)
@ -857,3 +858,32 @@ class ChatControl(ChatControlBase):
contact.our_chatstate = state
if contact.our_chatstate == 'active':
self.reset_kbd_mouse_timeout_vars()
def shutdown(self):
# Send 'gone' chatstate
self.send_chatstate('gone', self.contact.jid)
self.contact.chatstate = None
self.contact.our_chatstate = None
# Disconnect timer callbacks
gobject.source_remove(self.possible_paused_timeout_id)
gobject.source_remove(self.possible_inactive_timeout_id)
if self.print_time_timeout_id:
gobject.source_remove(self.print_time_timeout_id)
# Clean up systray
if gajim.interface.systray_enabled and self.nb_unread > 0:
gajim.interface.systray.remove_jid(self.contact.jid, self.account,
self.type)
def check_delete(self):
jid = self.contact.jid
if time.time() - gajim.last_message_time[self.account][jid] < 2:
# 2 seconds
dialog = dialogs.ConfirmationDialog(
#%s is being replaced in the code with JID
_('You just received a new message from "%s"' % jid),
_('If you close this tab and you have history disabled, '\
'this message will be lost.'))
if dialog.get_response() != gtk.RESPONSE_OK:
return True #stop the propagation of the event
return False

View File

@ -19,12 +19,21 @@ import gobject
import gtkgui_helpers
from common import gajim
from chat_control import ChatControl
from chat_control import ChatControlBase
from conversation_textview import ConversationTextview
from message_textview import MessageTextView
class PrivateChatControl(ChatControl):
TYPE_ID = 'pm'
def __init__(self, parent_win, contact, acct):
ChatControl.__init__(self, parent_win, contact, acct)
self.TYPE_ID = 'pm'
self.display_name = _('Private char')
class GroupchatControl(ChatControlBase):
TYPE_ID = 2
TYPE_ID = 'gc'
def __init__(self, parent_win, contact, acct):
ChatControlBase.__init__(self, self.TYPE_ID, parent_win,
@ -33,3 +42,42 @@ class GroupchatControl(ChatControlBase):
# muc attention states (when we are mentioned in a muc)
# if the room jid is in the list, the room has mentioned us
self.muc_attentions = []
def markup_tab_label(self, label_str, chatstate):
'''Markup the label if necessary. Returns a tuple such as:
(new_label_str, color)
either of which can be None
if chatstate is given that means we have HE SENT US a chatstate'''
num_unread = self.nb_unread
has_focus = self.parent_win.get_property('has-toplevel-focus')
current_tab = self.parent_win.get_active_control() == self
color = None
theme = gajim.config.get('roster_theme')
if chatstate == 'attention' and (not has_focus or not current_tab):
if jid not in self.muc_attentions:
self.muc_attentions.append(jid)
color = gajim.config.get_per('themes', theme,
'state_muc_directed_msg')
elif chatstate:
if chatstate == 'active' or (current_tab and has_focus):
if jid in self.muc_attentions:
self.muc_attentions.remove(jid)
color = gajim.config.get_per('themes', theme,
'state_active_color')
elif chatstate == 'newmsg' and (not has_focus or not current_tab) and\
jid not in self.muc_attentions:
color = gajim.config.get_per('themes', theme, 'state_muc_msg')
if color:
color = gtk.gdk.colormap_get_system().alloc_color(color)
# The widget state depend on whether this tab is the "current" tab
if current_tab:
nickname.modify_fg(gtk.STATE_NORMAL, color)
else:
nickname.modify_fg(gtk.STATE_ACTIVE, color)
if num_unread: # if unread, text in the label becomes bold
label_str = '<b>' + str(num_unread) + label_str + '</b>'
return (label_str, color)

View File

@ -85,7 +85,12 @@ class MessageWindow:
self.window.show_all()
def _on_window_delete(self, win, event):
print "MessageWindow._on_window_delete:", win, event
# Make sure all controls are okay with being deleted
for ctl in self._controls.values():
if not ctl.check_delete():
return True # halt the delete
# FIXME: Do based on type, main, never, peracct, pertype
if gajim.config.get('saveposition'):
# save the window size and position
x, y = win.get_position()
@ -96,8 +101,13 @@ class MessageWindow:
gajim.config.set('msgwin-height', height)
return False
def _on_window_destroy(self, win):
# FIXME
print "MessageWindow._on_window_destroy:", win
for ctl in self._controls.values():
ctl.shutdown()
self._controls.clear()
def new_tab(self, control):
assert(not self._controls.has_key(control.contact.jid))
@ -284,11 +294,21 @@ class MessageWindow:
for ctl in self._controls.values():
ctl.update_tags()
def get_control_from_jid(self, jid):
for ctl in self._controls.values():
if ctl.contact.jid == jid:
return ctl
return None
def get_control(self, arg):
'''Return the MessageControl for jid or n, where n is the notebook page index'''
if isinstance(arg, unicode):
jid = arg
for ctl in self._controls.values():
if ctl.contact.jid == jid:
return ctl
return None
else:
page_num = arg
notebook = self.notebook
if page_num == None:
page_num = notebook.get_current_page()
nth_child = notebook.get_nth_page(page_num)
return self._widgetToControl(nth_child)
def controls(self):
for ctl in self._controls.values():
@ -307,6 +327,41 @@ class MessageWindow:
ctl.print_time_timeout_id = gobject.timeout_add(300000,
ctl.print_time_timeout, None)
def move_to_next_unread_tab(self, forward):
ind = self.notebook.get_current_page()
current = ind
found = False
# loop until finding an unread tab or having done a complete cycle
while True:
if forward == True: # look for the first unread tab on the right
ind = ind + 1
if ind >= self.notebook.get_n_pages():
ind = 0
else: # look for the first unread tab on the right
ind = ind - 1
if ind < 0:
ind = self.notebook.get_n_pages() - 1
if ind == current:
break # a complete cycle without finding an unread tab
ctl = self.get_control(ind)
if ctl.nb_unread > 0:
found = True
break # found
if found:
self.notebook.set_current_page(ind)
else: # not found
if forward: # CTRL + TAB
if current < (self.notebook.get_n_pages() - 1):
self.notebook.next_page()
else: # traverse for ever (eg. don't stop at last tab)
self.notebook.set_current_page(0)
else: # CTRL + SHIFT + TAB
if current > 0:
self.notebook.prev_page()
else: # traverse for ever (eg. don't stop at first tab)
self.notebook.set_current_page(
self.notebook.get_n_pages() - 1)
class MessageWindowMgr:
'''A manager and factory for MessageWindow objects'''
@ -334,7 +389,6 @@ class MessageWindowMgr:
def _new_window(self):
win = MessageWindow()
# we track the lifetime of this window
win.window.connect('delete-event', self._on_window_delete)
win.window.connect('destroy', self._on_window_destroy)
return win
@ -344,17 +398,17 @@ class MessageWindowMgr:
return w
return None
def _on_window_delete(self, win, event):
# FIXME
print "MessageWindowMgr._on_window_delete:", win
def _on_window_destroy(self, win):
# FIXME
print "MessageWindowMgr._on_window_destroy:", win
# TODO: Clean up windows
for k in self._windows.keys():
if self._windows[k].window == win:
del self._windows[k]
return
# How was the window not in out list?!? Assert.
assert(False)
def get_window(self, jid):
for win in self._windows.values():
if win.get_control_from_jid(jid):
if win.get_control(jid):
return win
return None
def has_window(self, jid):
@ -384,9 +438,10 @@ class MessageWindowMgr:
return win
def get_control(self, jid):
'''Amonst all windows, return the MessageControl for jid'''
win = self.get_window(jid)
if win:
return win.get_control_from_jid(jid)
return win.get_control(jid)
return None
def windows(self):
@ -419,8 +474,11 @@ class MessageControl(gtk.VBox):
# Autoconnect glade signals
self.xml.signal_autoconnect(self)
def shutdown(self):
# NOTE: Derived classes MUST implement this
assert(False)
def draw_widgets(self):
pass # NOTE: Derived classes should implement this
pass # NOTE: Derived classes SHOULD implement this
def repaint_themed_widgets(self, theme):
pass # NOTE: Derived classes SHOULD implement this
def update_state(self):
@ -445,7 +503,14 @@ class MessageControl(gtk.VBox):
# NOTE: Derived classes SHOULD implement this
return None
def set_compact_view(self, state):
# NOTE: Derived classes MAY implement this
self.compact_view_current = state
def check_delete(self):
'''Called when a window has been asked to delete itself. If a control is
not in a suitable shutdown state this method should return True to halt
the delete'''
# NOTE: Derived classes MAY implement this
return False
def send_message(self, message, keyID = '', type = 'chat', chatstate = None):
'''Send the given message to the active tab'''

View File

@ -712,7 +712,7 @@ class RosterWindow:
if gajim.interface.msg_win_mgr.has_window(contact.jid):
jid = contact.jid
win = gajim.interface.msg_win_mgr.get_window(contact.jid)
ctl = win.get_control_from_jid(jid)
ctl = win.get_control(jid)
ctl.update_state()
name = contact.name