Window/control shutdown
This commit is contained in:
		
							parent
							
								
									c30ee542dc
								
							
						
					
					
						commit
						6036368b6e
					
				
					 4 changed files with 165 additions and 22 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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'''
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue