# -*- coding: utf-8 -*-
# Copyright (C) 2007 daelstorm. All rights reserved.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Original copyright below
# Copyright (c) 2003-2004 Hyriand. All rights reserved.

# Python core
from os.path import commonprefix
import os, re, time, sys

# Python modules
import gtk
import gobject
import locale
import pango

# Application specific
from pynicotine.logfacility import log
from pynicotine import slskmessages
from pynicotine import pluginsystem
from pynicotine.slskmessages import ToBeEncoded
from utils import InitialiseColumns, AppendLine, PopupMenu, FastListModel, string_sort_func, WriteLog, int_sort_func, Humanize, HumanSpeed, expand_alias, is_alias, EncodingsMenu, SaveEncoding, PressHeader, fixpath, IconNotebook, showCountryTooltip
from pynicotine.utils import _, findBestEncoding
from ticker import Ticker
from entrydialog import OptionDialog, input_box

ver = sys.version_info 

def GetCompletion(part, list):
	matches = GetCompletions(part, list)
	if len(matches) == 0:
		return None, 0
	if len(matches) == 1:
		return matches[0], 1
	else:
		return commonprefix([x.lower() for x in matches]), 0
def GetCompletions(part, list):
	lowerpart = part.lower()
	matches = [x for x in set(list) if x.lower().startswith(lowerpart) and len(x) >= len(part)]
	return matches

class RoomsControl:
	CMDS = set(["/alias ", "/unalias ", "/whois ", "/browse ", "/ip ", "/pm ", "/msg ", "/search ", "/usearch ", "/rsearch ",
		"/bsearch ", "/join ", "/leave ", "/add ", "/buddy ", "/rem ", "/unbuddy ", "/ban ", "/ignore ", "/ignoreip ", "/unban ", "/unignore ",
		"/clear ", "/part ", "/quit ", "/exit ", "/rescan ", "/tick ", "/nsa ", "/info ", "/detach ", "/attach ", "/reload"])
	
	def __init__(self, frame, ChatNotebook):
		self.frame = frame
		self.joinedrooms = {}
		self.autojoin = 1
		self.rooms = []
		config = self.frame.np.config.sections
		self.PrivateRooms =  config["private_rooms"]["rooms"]
		# Config cleanup
		for room,data in self.PrivateRooms.items():
			if "owner" not in data:
				self.PrivateRooms[room]["owner"] = None
			if "operator" in data:
				del self.PrivateRooms[room]["operator"]
		#self.PrivateRoomsMembership = config["private_rooms"]["membership"]
		
		self.clist = []
		self.roomsmodel = gtk.ListStore(str, int, int)
		frame.roomlist.RoomsList.set_model(self.roomsmodel)
		
		self.cols = InitialiseColumns(frame.roomlist.RoomsList,
			[_("Room"), 150, "text", self.RoomStatus],
			[_("Users"), -1, "number", self.RoomStatus],
		)
		self.cols[0].set_sort_column_id(0)
		self.cols[1].set_sort_column_id(1)
		self.roomsmodel.set_sort_func(1, self.PrivateRoomsSort, 1)
		#self.roomsmodel.set_sort_column_id(1, gtk.SORT_DESCENDING)
		#self.cols[1].set_sort_indicator(True)
		
		for i in range (2):
			parent = self.cols[i].get_widget().get_ancestor(gtk.Button)
			if parent:
				parent.connect('button_press_event', PressHeader)

		self.popup_room = None
		self.popup_menu = PopupMenu().setup(
			("#" + _("Join room"), self.OnPopupJoin, gtk.STOCK_JUMP_TO ),
			("#" + _("Leave room"), self.OnPopupLeave, gtk.STOCK_CLOSE),
			( "", None ),
			("#" + _("Enable Private Rooms"), self.OnEnablePrivateRooms, gtk.STOCK_OK),
			("#" + _("Disable Private Rooms"), self.OnDisablePrivateRooms, gtk.STOCK_CANCEL),
			( "", None ),
			("#" + _("Create Private Room"), self.OnPopupCreatePrivateRoom, gtk.STOCK_NEW),
			("#" + _("Disown Private Room"), self.OnPopupPrivateRoomDisown, gtk.STOCK_CLOSE),
			("#" + _("Cancel room membership"), self.OnPopupPrivateRoomDismember, gtk.STOCK_CANCEL),
			( "", None ),
			("#" + _("Join Public Room"), self.OnJoinPublicRoom, gtk.STOCK_DIALOG_WARNING),
			( "", None ),
			("#" + _("Refresh"), self.OnPopupRefresh, gtk.STOCK_REFRESH ),
		)
		
		items = self.popup_menu.get_children()
		self.Menu_Join, self.Menu_Leave, self.Menu_Empty1, self.Menu_PrivateRoom_Enable, self.Menu_PrivateRoom_Disable, self.Menu_Empty2, self.Menu_PrivateRoom_Create, self.Menu_PrivateRoom_Disown, self.Menu_PrivateRoom_Dismember, self.Menu_Empty3, self.Menu_JoinPublicRoom, self.Menu_Empty4, self.Menu_Refresh = items
		self.Menu_PrivateRoom_Enable.set_sensitive(False)
		self.Menu_PrivateRoom_Disable.set_sensitive(False)
		self.Menu_PrivateRoom_Create.set_sensitive(False)
		frame.roomlist.RoomsList.connect("button_press_event", self.OnListClicked)
		frame.roomlist.RoomsList.set_headers_clickable(True)

		frame.roomlist.HideRoomList.connect("clicked", self.OnShowRoomList)

		ChatNotebook.connect("switch-page", self.OnSwitchPage)
		try:
			ChatNotebook.connect("page-reordered", self.OnReorderedPage)
		except:
			# No PyGTK 2.10! Gosh, you really need to get with the times!
			pass
		self.frame.SetTextBG(self.frame.roomlist.RoomsList)
		self.frame.SetTextBG(self.frame.roomlist.CreateRoomEntry)
		self.frame.SetTextBG(self.frame.roomlist.SearchRooms)
		
	def IsPrivateRoomOwned(self, room):
		if room in self.PrivateRooms:
			#print self.PrivateRooms[room]
			if self.PrivateRooms[room]["owner"] == self.frame.np.config.sections["server"]["login"]:
				return True
		return False
		
	def IsPrivateRoomMember(self, room):
		if room in self.PrivateRooms:
			return True
		return False
	
	def IsPrivateRoomOperator(self, room):
		if room in self.PrivateRooms:
			if self.frame.np.config.sections["server"]["login"] in self.PrivateRooms[room]["operators"]:
				return True
		return False
		
	def PrivateRoomsSort(self, model, iter1, iter2, column):
		try:
			private1 = model.get_value(iter1, 2) * 10000
			private1 += model.get_value(iter1, 1)
		except:
			private1 = 0
		try:
			private2 = model.get_value(iter2, 2) * 10000
			private2 += model.get_value(iter2, 1)
		except:
			private2 = 0
		return cmp(private1, private2)
		#return cmp(val1+private1, val2+private2)


	def RoomStatus(self, column, cellrenderer, model, iter):

		if self.roomsmodel.get_value(iter, 2) >= 2:
			cellrenderer.set_property("underline", pango.UNDERLINE_SINGLE)
			cellrenderer.set_property("weight", pango.WEIGHT_BOLD)
		elif self.roomsmodel.get_value(iter, 2) >= 1:
			cellrenderer.set_property("weight", pango.WEIGHT_BOLD)
			cellrenderer.set_property("underline", pango.UNDERLINE_NONE)
		else:
			cellrenderer.set_property("weight", pango.WEIGHT_NORMAL)
			cellrenderer.set_property("underline", pango.UNDERLINE_NONE)
		self.frame.CellDataFunc(column, cellrenderer, model, iter)
		
	def OnReorderedPage(self, notebook, page, page_num, force=0):
		room_tab_order = {}
		# Find position of opened autojoined rooms
		for name, room in self.joinedrooms.items():
			if name not in self.frame.np.config.sections["server"]["autojoin"]:
				continue
			room_tab_order [ notebook.page_num(room.Main) ] = name
		pos = 1000
		# Add closed autojoined rooms as well
		for name in self.frame.np.config.sections["server"]["autojoin"]:
			if name not in self.joinedrooms:
				room_tab_order [ pos ] = name
				pos += 1
		# Sort by "position"
		rto = list(room_tab_order.keys())
		rto.sort()
		new_autojoin = []
		for roomplace in rto:
			new_autojoin.append(room_tab_order[roomplace])
		# Save
		self.frame.np.config.sections["server"]["autojoin"] = new_autojoin
		
	def OnSwitchPage(self, notebook, page, page_num, force=0):
		if self.frame.MainNotebook.get_current_page() != self.frame.MainNotebook.page_num(self.frame.hpaned1) and not force:
			return
		page = notebook.get_nth_page(page_num)
		for name, room in self.joinedrooms.items():
			if room.Main == page:
				gobject.idle_add(room.ChatEntry.grab_focus)
				# Remove hilite
				self.frame.Notifications.Clear("rooms", None, name)
					
	def ClearNotifications(self):
		if self.frame.MainNotebook.get_current_page() != self.frame.MainNotebook.page_num(self.frame.hpaned1):
			return
		page = self.frame.ChatNotebook.get_nth_page( self.frame.ChatNotebook.get_current_page())
		for name, room in self.joinedrooms.items():
			if room.Main == page:
				# Remove hilite
				self.frame.Notifications.Clear("rooms", None, name)
				
	def Focused(self, page, focused):
		if not focused:
			return
		for name, room in self.users.items():
			if room.Main == page:
				self.frame.Notifications.Clear("rooms", name)
			
	def OnShowRoomList(self, widget):

		self.frame.show_room_list1.set_active(1)
		
	def OnListClicked(self, widget, event):
		if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
			d = self.frame.roomlist.RoomsList.get_path_at_pos(int(event.x), int(event.y))
			if d:
				path, column, x, y = d
				room = self.roomsmodel.get_value(self.roomsmodel.get_iter(path), 0)
				if not room in self.joinedrooms.keys():
					self.frame.np.queue.put(slskmessages.JoinRoom(room))
			return True
		elif event.button == 3:
			return self.OnPopupMenu(widget, event)
		return False
		
	def OnPopupMenu(self, widget, event):
		if event.button != 3 or self.roomsmodel is None:
			return
		items = self.popup_menu.get_children()
		d = self.frame.roomlist.RoomsList.get_path_at_pos(int(event.x), int(event.y))
		if d:
			path, column, x, y = d
			room = self.roomsmodel.get_value(self.roomsmodel.get_iter(path), 0)
			if room in self.joinedrooms.keys():
				act = (False, True)
			else:
				act = (True, False)
		else:
			room = None
			act = (False, False)
		self.popup_room = room
		#prooms_enabled = bool(self.frame.np.config.sections["private_rooms"]["enabled"])
		prooms_enabled = True
		self.Menu_Join.set_sensitive(act[0])
		self.Menu_Leave.set_sensitive(act[1])
		#self.Menu_PrivateRoom_Create.set_sensitive(prooms_enabled) # Create private room
		self.Menu_PrivateRoom_Disown.set_sensitive(self.IsPrivateRoomOwned( self.popup_room)) # Disown
		self.Menu_PrivateRoom_Dismember.set_sensitive((prooms_enabled and self.IsPrivateRoomMember(self.popup_room) )) # Dismember
		self.popup_menu.popup(None, None, None, event.button, event.time)
	
	def OnPopupJoin(self, widget):
		self.frame.np.queue.put(slskmessages.JoinRoom(self.popup_room))
		
	def OnEnablePrivateRooms(self, widget):
		self.frame.np.queue.put(slskmessages.PrivateRoomToggle(True))
	def OnJoinPublicRoom(self, widget):
		# Everything but queue.put shouldn't be here, but the server doesn't send a confirmation when joining
		# public room. It would be clearer if we faked such a message ourself somewhere in the core
		if 'Public ' in self.joinedrooms:
			return
		room = ChatRoom(self, 'Public ', {}, meta = True)
		self.joinedrooms['Public '] = room
		angle = 0
		try:
			angle = int(self.frame.np.config.sections["ui"]["labelrooms"])
		except Exception, e:
			print e
			pass
		self.frame.ChatNotebook.append_page(room.Main, 'Public ', room.OnLeave, angle)
		room.CountUsers()
		self.frame.np.queue.put(slskmessages.JoinPublicRoom())
	def OnDisablePrivateRooms(self, widget):
		self.frame.np.queue.put(slskmessages.PrivateRoomToggle(False))
		
	def OnPopupCreatePrivateRoom(self, widget):
		room = input_box(self.frame, title=_('Nicotine+:')+" "+_("Create Private Room"),
		message=_('Enter the name of the private room you wish to create'),
		default_text='')
		if room:
			self.frame.np.queue.put(slskmessages.JoinRoom(room, 1))
			
	def OnPopupPrivateRoomDisown(self, widget):
		if self.IsPrivateRoomOwned(self.popup_room):
			self.frame.np.queue.put(slskmessages.PrivateRoomDisown(self.popup_room))
			del self.PrivateRooms[self.popup_room]
			self.SetPrivateRooms()
			
	def OnPopupPrivateRoomDismember(self, widget):
		if self.IsPrivateRoomMember(self.popup_room):
			self.frame.np.queue.put(slskmessages.PrivateRoomDismember(self.popup_room))
			del self.PrivateRooms[self.popup_room]
			self.SetPrivateRooms()
			
	def OnPopupLeave(self, widget):
		self.frame.np.queue.put(slskmessages.LeaveRoom(self.popup_room))
		
	def OnPopupRefresh(self, widget):
		self.frame.np.queue.put(slskmessages.RoomList())
		
	def JoinRoom(self, msg):
		if msg.room in self.joinedrooms:
			self.joinedrooms[msg.room].Rejoined(msg.users)
			return
		tab = ChatRoom(self, msg.room, msg.users)
		self.joinedrooms[msg.room] = tab
		if msg.private is not None:
			self.CreatePrivateRoom(msg.room, msg.owner, msg.operators)
		angle = 0
		try:
			angle = int(self.frame.np.config.sections["ui"]["labelrooms"])
		except Exception, e:
			print e
			pass
		self.frame.ChatNotebook.append_page(tab.Main, msg.room, tab.OnLeave, angle)
		
		self.frame.searchroomslist[msg.room] = self.frame.RoomSearchCombo_List.append([msg.room])
		tab.CountUsers()
		

	def SetRoomList(self, msg):
		
		if self.autojoin:
			self.autojoin = 0
			if self.joinedrooms.keys():
				list = self.joinedrooms.keys()
			else:
				list = self.frame.np.config.sections["server"]["autojoin"]

			for room in list:
				if room[-1:] != ' ':
					self.frame.np.queue.put(slskmessages.JoinRoom(room))
		self.roomsmodel.clear()
		self.frame.roomlist.RoomsList.set_model(None)
		self.roomsmodel.set_default_sort_func(lambda *args: -1)
		self.roomsmodel.set_sort_func(1, lambda *args: -1)
		self.roomsmodel.set_sort_column_id(-1, gtk.SORT_ASCENDING)

		self.rooms = []
		for room, users in msg.rooms:
			self.roomsmodel.append([room, users, 0])
			self.rooms.append(room)

		self.SetPrivateRooms(msg.ownedprivaterooms, msg.otherprivaterooms)
		self.frame.roomlist.RoomsList.set_model(self.roomsmodel)
		self.roomsmodel.set_sort_func(1, self.PrivateRoomsSort, 1)
		self.roomsmodel.set_sort_column_id(1, gtk.SORT_DESCENDING)
		self.roomsmodel.set_default_sort_func(None)
		#self.cols[1].set_sort_indicator(True)

		if self.frame.np.config.sections["words"]["roomnames"]:
			self.frame.chatrooms.roomsctrl.UpdateCompletions()
			self.frame.privatechats.UpdateCompletions()
			
	def SetPrivateRooms(self, ownedrooms=[], otherrooms=[]):
		myusername = self.frame.np.config.sections["server"]["login"]
		for room in ownedrooms:
			try:
				self.PrivateRooms[room[0]]['joined'] = room[1]
				if self.PrivateRooms[room[0]]['owner'] != myusername:
					log.addwarning(_("I remember the room %(room)s being owned by %(previous)s, but the server says its owned by %(new)s.") % {
							'room': room[0],
							'previous': self.PrivateRooms[room[0]]['owner'],
							'new': myusername
						})
				self.PrivateRooms[room[0]]['owner'] = myusername
			except KeyError:
				self.PrivateRooms[room[0]] = {"users": [], "joined": room[1], "operators": [],  "owner": myusername}
		for room in otherrooms:
			try:
				self.PrivateRooms[room[0]]['joined'] = room[1]
				if self.PrivateRooms[room[0]]['owner'] == myusername:
					log.addwarning(_("I remember the room %(room)s being owned by %(old)s, but the server says that's not true.") % {
							'room': room[0],
							'old': self.PrivateRooms[room[0]]['owner'],
						})
					self.PrivateRooms[room[0]]['owner'] = None
			except KeyError:
				self.PrivateRooms[room[0]] = {"users": [], "joined": room[1], "operators": [],  "owner": None}
		iter = self.roomsmodel.get_iter_root()
		while iter is not None:
			room = self.roomsmodel.get_value(iter, 0)
			lastiter = iter
			iter = self.roomsmodel.iter_next(iter)
			if self.IsPrivateRoomOwned(room) or self.IsPrivateRoomMember(room):
				self.roomsmodel.remove(lastiter)
		for room in self.PrivateRooms:
			num = self.PrivateRooms[room]["joined"]
			if self.IsPrivateRoomOwned(room):
				self.roomsmodel.prepend([room, num, 2])
			elif self.IsPrivateRoomMember(room):
				self.roomsmodel.prepend([room, num, 1])
				
	def CreatePrivateRoom(self, room, owner=None, operators=[]):
		if room in self.PrivateRooms:
			if operators is not None:
				for operator in operators:
					if operator not in self.PrivateRooms[room]["operators"]:
						self.PrivateRooms[room]["operators"].append(operator)
			self.PrivateRooms[room]["owner"] = owner
			return
		self.PrivateRooms[room] = {"users": [], "joined": 0, "operators": operators, "owned":False, "owner":owner}
		
	def PrivateRoomUsers(self, msg):
		rooms = self.PrivateRooms
		if msg.room not in rooms.keys():
			self.CreatePrivateRoom(msg.room)
			rooms[msg.room]["users"] = msg.users
			rooms[msg.room]["joined"] = msg.numusers

		else:
			rooms[msg.room]["users"] = msg.users
			rooms[msg.room]["joined"] = msg.numusers
		#self.PrivateRoomsOwned[msg.room]["users"] = msg.users
		self.SetPrivateRooms()
		#msg.debug()
		
	def PrivateRoomOwned(self, msg):
		rooms = self.PrivateRooms
		if msg.room not in rooms.keys():
			self.CreatePrivateRoom(msg.room)
			rooms[msg.room]["operators"] = msg.operators
		else:
			rooms[msg.room]["operators"] = msg.operators
		
		#msg.debug()
		
		self.SetPrivateRooms()
	def PrivateRoomAddUser(self, msg):
		rooms = self.PrivateRooms
		if msg.room in rooms.keys():
			if msg.user not in rooms[msg.room]["users"]:
				rooms[msg.room]["users"].append(msg.user)
		self.SetPrivateRooms()
	def PrivateRoomRemoveUser(self, msg):
		rooms = self.PrivateRooms
		if msg.room in rooms.keys():
			if msg.user in rooms[msg.room]["users"]:
				rooms[msg.room]["users"].remove(msg.user)
		self.SetPrivateRooms()
	def PrivateRoomOperatorAdded(self, msg):
		rooms = self.PrivateRooms
		if msg.room in rooms.keys():
			if self.frame.np.config.sections["server"]["login"] not in rooms[msg.room]["operators"]:
				rooms[msg.room]["operators"].append(self.frame.np.config.sections["server"]["login"])
		
		self.SetPrivateRooms()

	def PrivateRoomOperatorRemoved(self, msg):
		rooms = self.PrivateRooms
		if msg.room in rooms.keys():
			if self.frame.np.config.sections["server"]["login"] in rooms[msg.room]["operators"]:
				rooms[msg.room]["operators"].remove(self.frame.np.config.sections["server"]["login"])

		self.SetPrivateRooms()

	def PrivateRoomAddOperator(self, msg):
		rooms = self.PrivateRooms
		if msg.room in rooms.keys():
			if msg.user not in rooms[msg.room]["operators"]:
				rooms[msg.room]["operators"].append(msg.user)
		self.SetPrivateRooms()

	def PrivateRoomRemoveOperator(self, msg):
		rooms = self.PrivateRooms
		if msg.room in rooms.keys():
			if msg.user in rooms[msg.room]["operators"]:
				rooms[msg.room]["operators"].remove(msg.user)

		self.SetPrivateRooms()

	def PrivateRoomAdded(self, msg):
		rooms = self.PrivateRooms
		room = msg.room
		if room not in rooms:
			self.CreatePrivateRoom(room)
			#rooms[room]["operator"] = True
			self.frame.logMessage(_("You have been added to a private room: %(room)s") % {"room":room} )
		self.SetPrivateRooms()

		
	def PrivateRoomRemoved(self, msg):
		rooms = self.PrivateRooms
		if msg.room in rooms:
			del rooms[msg.room]
		self.SetPrivateRooms()
		
	def TogglePrivateRooms(self, enabled):
		self.frame.np.config.sections["server"]["private_chatrooms"] = enabled
		self.Menu_PrivateRoom_Enable.set_sensitive(not enabled)
		self.Menu_PrivateRoom_Disable.set_sensitive(enabled)
		self.Menu_PrivateRoom_Create.set_sensitive(enabled)
		
	def PrivateRoomDisown(self, msg):
		if msg.room in self.PrivateRooms.keys():
			if self.PrivateRooms[msg.room]["owner"] == self.frame.np.config.sections["server"]["login"]:
				self.PrivateRooms[msg.room]["owner"] = None
	
	def GetUserStats(self, msg):
		for room in self.joinedrooms.values():
			room.GetUserStats(msg.user, msg.avgspeed, msg.files)
	
	def GetUserStatus(self, msg):
		for room in self.joinedrooms.values():
			room.GetUserStatus(msg.user, msg.status)
			
	def SetUserFlag(self, user, flag):
		for room in self.joinedrooms.values():
			room.SetUserFlag(user, flag)

	def GetUserAddress(self, user):
		if user not in self.frame.np.users:
			self.frame.np.queue.put(slskmessages.GetPeerAddress(user))
		elif self.frame.np.users[user].addr is None:
			self.frame.np.queue.put(slskmessages.GetPeerAddress(user))

	def UserJoinedRoom(self, msg):
		if msg.room in self.joinedrooms:
			self.joinedrooms[msg.room].UserJoinedRoom(msg.username, msg.userdata)
			self.GetUserAddress(msg.username)
	
	def UserLeftRoom(self, msg):
		self.joinedrooms[msg.room].UserLeftRoom(msg.username)
	
	def TickerSet(self, msg):
		self.joinedrooms[msg.room].TickerSet(msg)

	def TickerAdd(self, msg):
		self.joinedrooms[msg.room].TickerAdd(msg)

	def TickerRemove(self, msg):
		self.joinedrooms[msg.room].TickerRemove(msg)

	def SayChatRoom(self, msg, text):
		if msg.user in self.frame.np.config.sections["server"]["ignorelist"]:
			return
		# Ignore chat messages from users who've been ignore-by-ip, no matter whether their username has changed
		# must have the user's IP for this to work.
		if msg.user in self.frame.np.users and type(self.frame.np.users[msg.user].addr) is tuple:
			ip, port = self.frame.np.users[msg.user].addr
			if self.frame.np.ipIgnored(ip):
				#print "ignored message from IP:", ip, msg.user
				return
		self.joinedrooms[msg.room].SayChatRoom(msg, text)
	def PublicRoomMessage(self, msg, text):
		try:
			room = self.joinedrooms['Public ']
		except KeyError:
			return
		#msg.user = "%s | %s" % (msg.room, msg.user)
		room.SayChatRoom(msg, text, public=True)
	
	def UpdateColours(self):
		self.frame.SetTextBG(self.frame.roomlist.RoomsList)
		self.frame.SetTextBG(self.frame.roomlist.CreateRoomEntry)
		self.frame.SetTextBG(self.frame.roomlist.SearchRooms)

		for room in self.joinedrooms.values():
			room.ChangeColours()
			
	def saveColumns(self):
		for room in self.frame.np.config.sections["columns"]["chatrooms"].keys()[:]:
			if room not in self.joinedrooms.keys():
				del self.frame.np.config.sections["columns"]["chatrooms"][room]
		for room in self.joinedrooms.values():
			room.saveColumns()
		

	def LeaveRoom(self, msg):
		room = self.joinedrooms[msg.room]
		if room.logfile is not None:
			room.logfile.close()
			room.logfile = None
		if self.frame.ChatNotebook.is_tab_detached(room.Main):
			self.frame.ChatNotebook.attach_tab(room.Main)
		self.frame.ChatNotebook.remove_page(room.Main)
		room.destroy()
		del self.joinedrooms[msg.room]
		if msg.room[-1:] != ' ': # meta rooms
			self.frame.RoomSearchCombo_List.remove(self.frame.searchroomslist[msg.room])
		if self.joinedrooms == {} and not self.frame.show_room_list1.get_active():
			win = OptionDialog(self.frame, _("You aren't in any chat rooms.") + " " + _("Open Room List?"), modal=True, status=None, option=False, third="")
			win.connect("response", self.frame.onOpenRoomList)
			win.set_title(_("Nicotine+")+": "+_("Open Room List?"))
			win.set_icon( self.frame.images["n"])
			win.show()
			
	def ConnClose(self):
		self.roomsmodel.clear()

		for room in self.joinedrooms.values():
			room.ConnClose()

		self.autojoin = 1
		
	def UpdateCompletions(self):
		self.clist = []
		config = self.frame.np.config.sections["words"]
		if config["tab"]:
			config = self.frame.np.config.sections["words"]
			clist = [self.frame.np.config.sections["server"]["login"], "nicotine"]
	
			if config["roomnames"]:
				clist += self.rooms
			if config["buddies"]:
				clist += [i[0] for i in self.frame.userlist.userlist]
			if config["aliases"]:
				clist += ["/"+k for k in self.frame.np.config.aliases.keys()]
			if config["commands"]:
				clist += self.CMDS
			self.clist = clist
		
		for room in self.joinedrooms.values():
			room.GetCompletionList(clist=list(self.clist))
			
def TickDialog(parent, default = ""):
	dlg = gtk.Dialog(title = _("Set ticker message"), parent = parent,
		buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK))
	dlg.set_default_response(gtk.RESPONSE_OK)
	
	t = 0
	
	dlg.set_border_width(10)
	dlg.vbox.set_spacing(10)
		
	l = gtk.Label(_("Set room ticker message:"))
	l.set_alignment(0, 0.5)
	dlg.vbox.pack_start(l, False, False)
	
	entry = gtk.Entry()
	entry.set_activates_default(True)
	entry.set_text(default)
	dlg.vbox.pack_start(entry, True, True)

	h = gtk.HBox(False, False)
	r1 = gtk.RadioButton()
	r1.set_label(_("Just this time"))
	r1.set_active(True)
	h.pack_start(r1, False, False)
	
	r2 = gtk.RadioButton(r1)
	r2.set_label(_("Always for this channel"))
	h.pack_start(r2, False, False)
	
	r3 = gtk.RadioButton(r1)
	r3.set_label(_("Default for all channels"))
	h.pack_start(r3, False, False)
	
	dlg.vbox.pack_start(h, True, True)
	
	dlg.vbox.show_all()

	result = None
	if dlg.run() == gtk.RESPONSE_OK:
		if r1.get_active():
			t = 0
		elif r2.get_active():
			t = 1
		elif r3.get_active():
			t = 2
		bytes = entry.get_text()
		try:
			result = unicode(bytes, "UTF-8")
		except UnicodeDecodeError:
			log.addwarning("We have a problem, PyGTK get_text does not seem to return UTF-8. Please file a bug report.")
			result = unicode(bytes, "UTF-8", "replace")
	dlg.destroy()
	return [t, result]

class ChatRoom:
	def __init__(self, roomsctrl, room, users, meta = False):
		self.roomsctrl = roomsctrl
		self.frame = roomsctrl.frame
		#self.tooltips = self.frame.tooltips

		gtk.glade.set_custom_handler(self.get_custom_widget)
		
		self.wTree = gtk.glade.XML(os.path.join(os.path.dirname(os.path.realpath(__file__)), "chatrooms.glade" ), None, 'nicotine' ) 
		widgets = self.wTree.get_widget_prefix("")
		for i in widgets:
			name = gtk.glade.get_widget_name(i)
			self.__dict__[name] = i
		self.ChatRoomTab.remove(self.Main)
		self.ChatRoomTab.destroy()
	
		self.wTree.signal_autoconnect(self)
		
		#if not self.frame.np.config.sections["ui"]["tooltips"]:
		#	self.tooltips.disable()
		self.room = room
		self.lines = []
		self.logfile = None
		self.leaving = 0
		self.meta = meta # not a real room if set to True
		config = self.frame.np.config.sections
		if not config["ticker"]["hide"]:
			self.Ticker.show()
		
		self.OnShowChatButtons(show=(not config["ui"]["chat_hidebuttons"]))
			
		if self.frame.translux:
			self.tlux_roomlog = lambda: self.RoomLog.get_window(gtk.TEXT_WINDOW_TEXT)
			self.tlux_chat = lambda: self.ChatScroll.get_window(gtk.TEXT_WINDOW_TEXT)
			self.frame.translux.subscribe(self.RoomLog, self.tlux_roomlog)
			self.frame.translux.subscribe(self.ChatScroll, self.tlux_chat)
			self.RoomLog.get_parent().get_vadjustment().connect("value-changed", lambda *args: self.RoomLog.queue_draw())
			self.ChatScroll.get_parent().get_vadjustment().connect("value-changed", lambda *args: self.ChatScroll.queue_draw())
			self.ChatScroll.get_parent().get_hadjustment().connect("value-changed", lambda *args: self.ChatScroll.queue_draw())
		self.clist = []
		self.Elist = {}
		self.encoding, m = EncodingsMenu(self.frame.np, "roomencoding", room)
		self.EncodingStore = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
		self.Encoding.set_size_request(100, -1)
		self.Encoding.set_model(self.EncodingStore)
		cell = gtk.CellRendererText()
		self.Encoding.pack_start(cell, True)
		self.Encoding.add_attribute(cell, 'text', 0)
		cell2 = gtk.CellRendererText()
		self.Encoding.pack_start(cell2, False)
		self.Encoding.add_attribute(cell2, 'text', 1)
	
		for item in m:
			self.Elist[item[1]] = self.EncodingStore.append([item[1], item[0] ])
			if self.encoding == item[1]:
				self.Encoding.set_active_iter(self.Elist[self.encoding])

		self.Ticker.entry.connect("button_press_event", self.OnTickerClicked)
		self.Ticker.entry.connect("focus-in-event", self.OnTickerFocus)
		self.Ticker.entry.connect("focus-out-event", self.OnTickerFocus)
		
		if self.frame.SEXY and config["ui"]["spellcheck"]:
			import sexy
			self.ChatEntryBox.remove(self.ChatEntry)
			self.ChatEntry.destroy()
			self.ChatEntry = sexy.SpellEntry()
			self.ChatEntry.show()
			self.ChatEntry.connect("activate", self.OnEnter)
			
			self.ChatEntry.connect("key_press_event", self.OnKeyPress)
			self.ChatEntryBox.pack_start(self.ChatEntry, True, True, 0)
			
		
		self.midwaycompletion = False # True if the user just used tab completion
		self.completions = {} # Holds temp. information about tab completoin
		completion = gtk.EntryCompletion()
		self.ChatEntry.set_completion(completion)
		liststore = gtk.ListStore(gobject.TYPE_STRING)
		completion.set_model(liststore)
		completion.set_text_column(0)

		completion.set_match_func(self.frame.EntryCompletionFindMatch, self.ChatEntry)
		completion.connect("match-selected", self.frame.EntryCompletionFoundMatch, self.ChatEntry)
		
		self.Log.set_active(config["logging"]["chatrooms"])
		if not self.Log.get_active():
			self.Log.set_active((self.room in config["logging"]["rooms"]))

		if room in config["server"]["autojoin"]:
			self.AutoJoin.set_active(True)
		statusiconwidth = self.frame.images["offline"].get_width()+4
		self.cols = cols = InitialiseColumns(self.UserList, 
			[_("Status"), statusiconwidth, "pixbuf"],
			[_("Country"), 25, "pixbuf"],
			[_("User"), 100, "text", self.UserColumnDraw],
			[_("Speed"), 0, "number", self.frame.CellDataFunc],
			[_("Files"), 0, "number", self.frame.CellDataFunc],
		)
		cols[0].set_sort_column_id(5)
		cols[1].set_sort_column_id(8)
		cols[2].set_sort_column_id(2)
		cols[3].set_sort_column_id(6)
		cols[4].set_sort_column_id(7)
		cols[0].get_widget().hide()
		cols[1].get_widget().hide()
		if room not in config["columns"]["chatrooms"]:
			config["columns"]["chatrooms"][room] = [1, 1, 1, 1, 1]
		if len(config["columns"]["chatrooms"][room]) != 5:	# Insert new column to old settings.
			config["columns"]["chatrooms"][room].insert(1, 1)
		for i in range (5):
			parent = cols[i].get_widget().get_ancestor(gtk.Button)
			if parent:
				parent.connect('button_press_event', PressHeader)
			# Read Show / Hide column settings from last session
			cols[i].set_visible(config["columns"]["chatrooms"][room][i])
		if config["columns"]["hideflags"]:
			cols[1].set_visible(0)
			config["columns"]["chatrooms"][room][1] = 0
		self.users = {}

		self.usersmodel = gtk.ListStore(gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_INT, gobject.TYPE_INT, gobject.TYPE_STRING)

		for user in users.keys():
			img = self.frame.GetStatusImage(users[user].status)
			flag = users[user].country
			if flag is not None:
				flag = "flag_"+flag
				self.frame.flag_users[user] = flag
			else:
				flag = self.frame.GetUserFlag(user)
			#hspeed = Humanize(users[user].avgspeed)
			hspeed = HumanSpeed(users[user].avgspeed)
			hfiles = Humanize(users[user].files)
			iter = self.usersmodel.append([img, self.frame.GetFlagImage(flag), user, hspeed, hfiles, users[user].status, users[user].avgspeed, users[user].files, flag])
			self.users[user] = iter
			self.roomsctrl.GetUserAddress(user)
		self.usersmodel.set_sort_column_id(2, gtk.SORT_ASCENDING)
		
		self.UpdateColours()
		self.UserList.set_model(self.usersmodel)
		self.UserList.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, [('text/plain', 0, 2)], gtk.gdk.ACTION_COPY)
		self.UserList.connect("drag_data_get", self.drag_data_get_data)
		self.UserList.set_property("rules-hint", True)
		self.popup_menu_privaterooms = PopupMenu(self.frame)
		self.popup_menu = popup = PopupMenu(self.frame)
		popup.setup(
			("USER", "", popup.OnCopyUser),
			("", None),
			("#" + _("Send _message"), popup.OnSendMessage, gtk.STOCK_EDIT),
			("", None),
			("#" + _("Show IP a_ddress"), popup.OnShowIPaddress, gtk.STOCK_NETWORK),
			("#" + _("Get user i_nfo"), popup.OnGetUserInfo, gtk.STOCK_DIALOG_INFO),
			("#" + _("Brow_se files"), popup.OnBrowseUser, gtk.STOCK_HARDDISK),
			("#" + _("Gi_ve privileges"), popup.OnGivePrivileges, gtk.STOCK_JUMP_TO),
			("", None),
			("$" + _("_Add user to list"), popup.OnAddToList),
			("$" + _("_Ban this user"), popup.OnBanUser),
			("$" + _("_Ignore this user"), popup.OnIgnoreUser),
			("$" + _("B_lock this user's IP Address"), popup.OnBlockUser),
			("$" + _("Ignore this user's IP Address"), popup.OnIgnoreIP),
			("", None),
			("#" + _("Sear_ch this user's files"), popup.OnSearchUser, gtk.STOCK_FIND),
			(1, _("Private rooms"), self.popup_menu_privaterooms, self.OnPrivateRooms),
		)
		items = self.popup_menu.get_children()
		self.Menu_SendMessage = items[2]
		self.Menu_ShowIPaddress = items[4]
		self.Menu_GetUserInfo = items[5]
		self.Menu_BrowseUser = items[6]
		self.Menu_GivePrivileges = items[7]
		self.Menu_AddToList = items[9]
		self.Menu_BanUser = items[10]
		self.Menu_IgnoreUser = items[11]
		self.Menu_BlockUser = items[12]
		self.Menu_IgnoreIP = items[13]
		self.Menu_SearchUser = items[15]
		self.Menu_PrivateRooms = items[16]
		img = gtk.Image()
		img.set_from_pixbuf(self.frame.images["money"])
		self.Menu_GivePrivileges.set_image(img)
		self.UserList.connect("button_press_event", self.OnPopupMenu)

		self.ChatEntry.grab_focus()
		self.ChatEntryBox.set_focus_child(self.ChatEntry)
		
		self.logpopupmenu = PopupMenu(self.frame).setup(
			("#" + _("Find"), self.OnFindLogWindow, gtk.STOCK_FIND),
			("", None),
			("#" + _("Copy"), self.OnCopyRoomLog, gtk.STOCK_COPY),
			("#" + _("Copy All"), self.OnCopyAllRoomLog, gtk.STOCK_COPY),
			("", None),
			("#" + _("Clear log"), self.OnClearRoomLog, gtk.STOCK_CLEAR),
		)
		self.RoomLog.connect("button-press-event", self.OnPopupRoomLogMenu)
		
		self.chatpopmenu = PopupMenu(self.frame).setup(
			("#" + _("Find"), self.OnFindChatLog, gtk.STOCK_FIND),
			("", None),
			("#" + _("Copy"), self.OnCopyChatLog, gtk.STOCK_COPY),
			("#" + _("Copy All"), self.OnCopyAllChatLog, gtk.STOCK_COPY),
			("", None),
			("#" + _("Clear log"), self.OnClearChatLog, gtk.STOCK_CLEAR),
		)
		self.ChatScroll.connect("button-press-event", self.OnPopupChatRoomMenu)
		self.buildingcompletion = False
		self.GetCompletionList(clist=list(self.roomsctrl.clist))
		if config["logging"]["readroomlogs"]:
			self.ReadRoomLogs()
		self.CountUsers()

	def RoomStatus(self, column, cellrenderer, model, iter):

		cellrenderer.set_property("weight", colour)
		
	def ReadRoomLogs(self):
		config = self.frame.np.config.sections
		log = os.path.join(config["logging"]["roomlogsdir"], fixpath(self.room.replace(os.sep, "-")) + ".log")
		try:
			roomlines = int(config["logging"]["readroomlines"])
		except:
			roomlines = 15
		try:
			encodings = ['UTF-8'] # New style logging, always in UTF-8
			try:
				encodings.append(config["server"]["roomencoding"][self.room]) # Old style logging, room dependent
			except KeyError:
				pass
			f = open(log, "r")
			logfile = f.read()
			f.close()
			loglines = logfile.split("\n")
			for bytes in loglines[ - roomlines : -1 ]:
				l = findBestEncoding(bytes, encodings)
				# Try to parse line for username
				if len(l) > 20 and l[10].isspace() and l[11].isdigit() and l[20] in ("[", "*"):
					line = l[11:]
					if l[20] == "[" and l[20:].find("] ") != -1:
						namepos = l[20:].find("] ")
						user = l[21:20+namepos].strip()
						user = user.encode('UTF-8') # this could go screwy! But there's no other way without logging raw bytes in the log file
						self.getUserTag(user)
						usertag = self.tag_users[user]
					else:
						user = None
						usertag = None
					if user == config["server"]["login"]:
						tag = self.tag_local
					elif l[20] == "*":
						tag = self.tag_me
					elif l[20+namepos:].upper().find(config["server"]["login"].upper()) > -1:
						tag = self.tag_hilite
					else:
						tag = self.tag_remote
				else:
					line = l
					user = None
					tag = None
					usertag = None
				timestamp_format=self.frame.np.config.sections["logging"]["rooms_timestamp"]

				line = re.sub("\s\s+", "  ", line)
				line += "\n"
				if user != config["server"]["login"]:
					self.lines.append(AppendLine(self.ChatScroll, self.frame.CensorChat(line), tag, username=user, usertag=usertag, timestamp_format=""))
				else:
					self.lines.append(AppendLine(self.ChatScroll, line, tag, username=user, usertag=usertag, timestamp_format=""))
			if len(loglines[ - roomlines : -1 ]) > 0:
				self.lines.append(AppendLine(self.ChatScroll, _("--- old messages above ---"), self.tag_hilite))
			gobject.idle_add(self.frame.ScrollBottom, self.ChatScroll.get_parent())
		except IOError, e:
			pass

	def on_key_press_event(self, widget, event):
		key = gtk.gdk.keyval_name(event.keyval)
		# Match against capslock + control and control
		if key in ( "f", "F") and event.state  in (gtk.gdk.CONTROL_MASK, gtk.gdk.LOCK_MASK|gtk.gdk.CONTROL_MASK) :
			self.OnFind(widget)
		elif key in ( "F3"):
			self.OnFind(widget, repeat=True)

	def OnFind(self, widget, repeat=False):
		self.frame.OnFindTextview(None, widget, repeat=repeat)

	def OnFindLogWindow(self, widget):
		self.frame.OnFindTextview(None, self.RoomLog)
		
	def OnFindChatLog(self, widget):
		self.frame.OnFindTextview(None, self.ChatScroll)
		
	def drag_data_get_data(self, treeview, context, selection, target_id, etime):
		treeselection = treeview.get_selection()
		model, iter = treeselection.get_selected()
		user = model.get_value(iter, 2)
		#data = (status, flag, user, speed, files)
		selection.set(selection.target, 8, user)
			
	def get_custom_widget(self, widget, string0, id, string1, string2, int1=None, int2=None, ):
		if id == "Ticker":
			t = Ticker()
			return t
		else:
			return gtk.Label(_("(custom widget: %s)") % id)
			
	def destroy(self):
		if self.frame.translux and self.tlux_roomlog:
			self.frame.translux.unsubscribe(self.tlux_roomlog)
			self.frame.translux.unsubscribe(self.tlux_chat)
		self.Main.destroy()
		
	def OnPrivateRooms(self, widget):
		if self.popup_menu.user == None or self.popup_menu.user == self.frame.np.config.sections["server"]["login"]:
			return False
		user = self.popup_menu.user
		items = []

		popup = self.popup_menu_privaterooms
		popup.clear()
		popup.set_user(self.popup_menu.user)
		#print self.roomsctrl.PrivateRooms
		for room in self.roomsctrl.PrivateRooms:
			if not (self.roomsctrl.IsPrivateRoomOwned(room) or self.roomsctrl.IsPrivateRoomOperator(room)):
				continue
			if user in self.roomsctrl.PrivateRooms[room]["users"]:
				items.append(("#" + _("Remove from private room %s" %room), popup.OnPrivateRoomRemoveUser, gtk.STOCK_REMOVE, room))
			else:
				items.append(("#" + _("Add to private room %s" %room), popup.OnPrivateRoomAddUser, gtk.STOCK_ADD, room))
			if self.roomsctrl.IsPrivateRoomOwned(room):
				if self.popup_menu.user in self.roomsctrl.PrivateRooms[room]["operators"]:
					items.append(("#" + _("Remove as operator of %s" %room), popup.OnPrivateRoomRemoveOperator, gtk.STOCK_REMOVE, room))
				else:
					items.append(("#" + _("Add as operator of %s" %room), popup.OnPrivateRoomAddOperator, gtk.STOCK_ADD, room))

		popup.setup(*items)
		
		return True
		
	def OnPrivateRoomsUser(self, widget, popup=None):
		if popup is None:
			return
		menu = popup
		user = menu.user
		items = menu.get_children()
		
		act = False
		
		return True
	
	def OnPopupMenu(self, widget, event):
		items = self.popup_menu.get_children()
		d = self.UserList.get_path_at_pos(int(event.x), int(event.y))
		if not d:
			return
		path, column, x, y = d
		user = self.usersmodel.get_value(self.usersmodel.get_iter(path), 2)
		
		# Double click starts a private message
		if event.button != 3:
			if event.type == gtk.gdk._2BUTTON_PRESS:
				self.frame.privatechats.SendMessage(user, None, 1)
				self.frame.ChangeMainPage(None, "private")
			return
		self.popup_menu.editing = True
		self.popup_menu.set_user(user)
		me = (self.popup_menu.user == None or self.popup_menu.user == self.frame.np.config.sections["server"]["login"])
		
		#self.Menu_SendMessage
		#self.Menu_ShowIPaddress
		#self.Menu_GetUserInfo
		#self.Menu_BrowseUser
		#self.Menu_GivePrivileges

		self.Menu_AddToList.set_active(user in [i[0] for i in self.frame.np.config.sections["server"]["userlist"]])
		self.Menu_BanUser.set_active(user in self.frame.np.config.sections["server"]["banlist"])
		self.Menu_IgnoreUser.set_active(user in self.frame.np.config.sections["server"]["ignorelist"])
		self.Menu_BlockUser.set_active(self.frame.UserIpIsBlocked(user))
		self.Menu_BlockUser.set_sensitive(not me)
		self.Menu_IgnoreIP.set_active(self.frame.UserIpIsIgnored(user))
		self.Menu_IgnoreIP.set_sensitive(not me) 
		#self.Menu_SearchUser
		self.Menu_PrivateRooms.set_sensitive(not me)

		self.popup_menu.editing = False	
		self.popup_menu.popup(None, None, None, event.button, event.time)
		

	
	def OnShowChatHelp(self, widget):
		self.frame.OnAboutChatroomCommands(widget, self.GetTabParent(self.Main))

	def OnShowChatButtons(self, show=True):
		for widget in self.HideStatusLog, self.HideUserList, self.ShowChatHelp:
			if show:
				widget.show()
			else:
				widget.hide()
		if self.frame.np.config.sections["ui"]["speechenabled"] and show:
			self.Speech.show()
		else:
			self.Speech.hide()
				
				
	def OnHideStatusLog(self, widget):
		act = widget.get_active()
		if act:
			self.RoomLogWindow.hide()
			self.HideStatusLogImage.set_from_stock(gtk.STOCK_GO_DOWN, 1)
		else:
			self.RoomLogWindow.show()
			self.HideStatusLogImage.set_from_stock(gtk.STOCK_GO_UP, 1)


	def OnHideUserList(self, widget):
		act = widget.get_active()
		if act:
			self.vbox5.hide()
			self.HideUserListImage.set_from_stock(gtk.STOCK_GO_BACK, 1)
		else:
			self.vbox5.show()
			self.HideUserListImage.set_from_stock(gtk.STOCK_GO_FORWARD, 1)

	
	def TickerSet(self, msg):
		self.Ticker.set_ticker({})
		for user in msg.msgs.keys():
			if user in self.frame.np.config.sections["server"]["ignorelist"] or self.frame.UserIpIsIgnored(user):
				# User ignored, ignore Ticker messages
				return
			self.Ticker.add_ticker(user, msg.msgs[user])

	def TickerAdd(self, msg):
		user = msg.user
		if user in self.frame.np.config.sections["server"]["ignorelist"] or self.frame.UserIpIsIgnored(user):
			# User ignored, ignore Ticker messages
			return
		self.Ticker.add_ticker(msg.user, msg.msg)

	def TickerRemove(self, msg):
		self.Ticker.remove_ticker(msg.user)
		
	def SayChatRoom(self, msg, text, public=False):
		text = re.sub("\s\s+", "  ", text)
		login = self.frame.np.config.sections["server"]["login"]
		user = msg.user
		if user == login:
			tag = self.tag_local
		elif text.upper().find(login.upper()) > -1:
			tag = self.tag_hilite

		else:
			tag = self.tag_remote
		
		if user != login:
			if tag == self.tag_hilite:
				self.frame.ChatNotebook.request_hilite(self.Main)
				if self.frame.ChatNotebook.is_tab_detached(self.Main):
					if not self.frame.ChatNotebook.is_detached_tab_focused(self.Main):
						self.frame.Notifications.Add("rooms", user, self.room, tab=False)
				else:
					self.frame.ChatRequestIcon(1, self.Main)
						
					# add hilite to trayicon
					if self.frame.ChatNotebook.get_current_page() != self.frame.ChatNotebook.page_num(self.roomsctrl.joinedrooms[self.room].Main) or self.frame.MainNotebook.get_current_page() != self.frame.MainNotebook.page_num(self.frame.hpaned1) or not self.frame.is_mapped:
						if self.room not in self.frame.TrayApp.tray_status["hilites"]["rooms"]:
							self.frame.Notifications.Add("rooms", user, self.room, tab=True)
				#else:
					#self.MainWindow.set_urgency_hint(False)
			else:
				self.frame.ChatNotebook.request_changed(self.Main)
				if self.frame.ChatNotebook.is_tab_detached(self.Main):
					pass
				else:
					self.frame.ChatRequestIcon(0)

		if text[:4] == "/me ":
			if public:
				line = "%s | * %s %s" % (msg.room, user, text[4:])
			else:
				line = "* %s %s" % (user, text[4:])
			speech = line[2:]
			tag = self.tag_me
		else:
			if public:
				line = "%s | [%s] %s" % (msg.room, user, text)
			else:
				line = "[%s] %s" % (user, text)
			speech = text

		if len(self.lines) >= 400:
			buffer = self.ChatScroll.get_buffer()
			start = buffer.get_start_iter()
			end = buffer.get_iter_at_line(1)
			self.ChatScroll.get_buffer().delete(start, end)
			del self.lines[0]

		line = "\n-- ".join(line.split("\n"))
		if self.Log.get_active():
			self.logfile = WriteLog(self.logfile, self.frame.np.config.sections["logging"]["roomlogsdir"], self.room, line)
		self.getUserTag(user)
		timestamp_format=self.frame.np.config.sections["logging"]["rooms_timestamp"]
		if user != login:
			self.lines.append(AppendLine(self.ChatScroll, self.frame.CensorChat(line), tag, username=user, usertag=self.tag_users[user], timestamp_format=timestamp_format))
			if self.Speech.get_active():
				self.frame.Notifications.new_tts(self.frame.np.config.sections["ui"]["speechrooms"] % {"room": self.room, "user": self.frame.Notifications.tts_clean(user), "message": self.frame.Notifications.tts_clean(speech)} )
		else:
			self.lines.append(AppendLine(self.ChatScroll, line, tag, username=user, usertag=self.tag_users[user], timestamp_format=timestamp_format))
		
			
	def getUserTag(self, user):
		if user not in self.users:
			color = "useroffline"
		else:
			color = self.getUserStatusColor(self.usersmodel.get_value(self.users[user], 5))
		if user not in self.tag_users:
			self.tag_users[user] = self.makecolour(self.ChatScroll.get_buffer(), color, user)
			return
		else:
			self.changecolour(self.tag_users[user], color)
	
		
	def threadAlias(self, alias):
		text = expand_alias(self.frame.np.config.aliases, alias)
		if not text:
			return
		if text[:2] == "//":
			text = text[1:]
		self.frame.np.queue.put(slskmessages.SayChatroom(self.room, ToBeEncoded(self.frame.AutoReplace(text), self.encoding)))

			
	def OnEnter(self, widget):
		bytes = widget.get_text()
		try:
			text = unicode(bytes, "UTF-8")
		except UnicodeDecodeError:
			log.addwarning("We have a problem, PyGTK get_text does not seem to return UTF-8. Please file a bug report.")
			text = unicode(bytes, "UTF-8", "replace")
		if not text:
			widget.set_text("")
			return
		if is_alias(self.frame.np.config.aliases, text):
			import thread
			thread.start_new_thread(self.threadAlias, (text,))
			widget.set_text("")
			return
		
		s = text.split(" ", 1) # string
		cmd = s[0]
		if len(s) == 2:
			args = s[1]
		else:
			args = ""
		s = bytes.split(" ", 1) # bytes
		if len(s) == 2:
			byteargs = s[1]
		else:
			byteargs = ""

		if cmd in ("/alias", "/al"):
			AppendLine(self.ChatScroll, self.frame.np.config.AddAlias(args), self.tag_remote, "")
			if self.frame.np.config.sections["words"]["aliases"]:
				self.frame.chatrooms.roomsctrl.UpdateCompletions()
				self.frame.privatechats.UpdateCompletions()
		elif cmd in ("/unalias", "/un"):
			AppendLine(self.ChatScroll, self.frame.np.config.Unalias(args), self.tag_remote, "")
			if self.frame.np.config.sections["words"]["aliases"]:
				self.frame.chatrooms.roomsctrl.UpdateCompletions()
				self.frame.privatechats.UpdateCompletions()
		elif cmd in ["/w", "/whois", "/info"]:
			if byteargs:
				self.frame.LocalUserInfoRequest(byteargs)
				self.frame.OnUserInfo(None)
		elif cmd in ["/b", "/browse"]:
			if byteargs:
				self.frame.BrowseUser(byteargs)
				self.frame.OnUserBrowse(None)
		elif cmd == "/nsa":
			if byteargs:
				self.frame.LocalUserInfoRequest(byteargs)
				self.frame.BrowseUser(byteargs)
				self.frame.OnUserInfo(None)
		elif cmd == "/ip":
			if byteargs:
				user = byteargs
				if user not in self.frame.np.ip_requested:
					self.frame.np.ip_requested.append(user)
				self.frame.np.queue.put(slskmessages.GetPeerAddress(user))
		elif cmd == "/pm":
			if byteargs:
				self.frame.privatechats.SendMessage(byteargs, None, 1)
				self.frame.OnPrivateChat(None)
		elif cmd in ["/m", "/msg"]:
			if byteargs:
				s = byteargs.split(" ", 1)
				user = s[0]
				if len(s) == 2:
					msg = s[1]
				else:
					msg = None
				self.frame.privatechats.SendMessage(user, msg)
		elif cmd in ["/s", "/search"]:
			if args:
				self.frame.Searches.DoSearch(args, 0)
				self.frame.OnSearch(None)
		elif cmd in ["/us", "/usearch"]:
			s = byteargs.split(" ", 1)
			if len(s) == 2:
				self.frame.Searches.DoSearch(s[1], 3, [s[0]])
				self.frame.OnSearch(None)
		elif cmd in ["/rs", "/rsearch"]:
			if args:
				self.frame.Searches.DoSearch(args, 1)
				self.frame.OnSearch(None)
		elif cmd in ["/bs", "/bsearch"]:
			if args:
				self.frame.Searches.DoSearch(args, 2)
				self.frame.OnSearch(None)
		elif cmd in ["/j", "/join"]:
			if byteargs:
				self.frame.np.queue.put(slskmessages.JoinRoom(byteargs))
		elif cmd in ["/l", "/leave", "/p", "/part"]:
			if byteargs:
				self.frame.np.queue.put(slskmessages.LeaveRoom(byteargs))
			else:
				self.frame.np.queue.put(slskmessages.LeaveRoom(self.room))
		elif cmd in ["/ad", "/add", "/buddy"]:
			if byteargs:
				self.frame.userlist.AddToList(byteargs)
		elif cmd in ["/rem", "/unbuddy"]:
			if byteargs:
				self.frame.userlist.RemoveFromList(byteargs)
		elif cmd == "/ban":
			if byteargs:
				self.frame.BanUser(byteargs)
		elif cmd == "/ignore":
			if byteargs:
				self.frame.IgnoreUser(byteargs)
		elif cmd == "/ignoreip":
			if byteargs:
				self.frame.IgnoreIP(byteargs)
		elif cmd == "/nuke":
			if byteargs:
				self.frame.BanUser(byteargs)
				self.frame.IgnoreUser(byteargs)
		elif cmd == "/unban":
			if byteargs:
				self.frame.UnbanUser(byteargs)
		elif cmd == "/unignore":
			if byteargs:
				self.frame.UnignoreUser(byteargs)
		elif cmd in ["/clear", "/cl"]:
			self.ChatScroll.get_buffer().set_text("")
			self.lines = []
		elif cmd in ["/a", "/away"]:
			self.frame.OnAway(None)
		elif cmd in ["/q", "/quit", "/exit"]:
			self.frame.OnExit(None)
			return # Avoid gsignal warning
		elif cmd == "/now":
			self.NowPlayingThread()
		elif cmd == "/detach":
			self.Detach()
		elif cmd == "/attach":
			self.frame.ChatNotebook.attach_tab(self.Main)
			gobject.idle_add(self.frame.ScrollBottom, self.ChatScroll.get_parent())
		elif cmd == "/rescan":
			self.frame.BothRescan()
		elif cmd in ["/tick", "/t"]:
			self.frame.np.queue.put(slskmessages.RoomTickerSet(self.room, ToBeEncoded(args, self.encoding)))
		elif cmd in ("/tickers",):
			self.showTickers()
		#elif cmd in ('/reload',):
			#self.frame.pluginhandler.reread()
			#self.frame.pluginhandler = pluginsystem.PluginHandler(self.frame)
		elif cmd[:1] == "/" and self.frame.pluginhandler.TriggerPublicCommandEvent(self.room, cmd[1:], args):
			pass
		elif cmd and cmd[:1] == "/" and cmd != "/me" and cmd[:2] != "//":
			self.frame.logMessage(_("Command %s is not recognized") % text)
			return
		else:
			if text[:2] == "//":
				text = text[1:]
			tuple = self.frame.pluginhandler.OutgoingPublicChatEvent(self.room, text)
			if tuple != None:
				(r, text) = tuple
				self.Say(self.frame.AutoReplace(text))
				self.frame.pluginhandler.OutgoingPublicChatNotification(self.room, text)
			#else:
			#	self.frame.logMessage(_("Pluginsystem decided to shut me up"))
		self.ChatEntry.set_text("")
	
	def showTickers(self):
		tickers = self.Ticker.get_tickers()
		header = _("All ticker messages for %(room)s:") % {'room':self.room}
		self.frame.logMessage("%s\n%s" % (header, "\n".join(["%s: %s" % (user, msg) for (user, msg) in tickers])))
	def Detach(self, widget = None):
		self.frame.ChatNotebook.detach_tab(self.Main, _("Nicotine+ Chatroom: %s") % self.room)
		gobject.idle_add(self.frame.ScrollBottom, self.ChatScroll.get_parent())
		
	def Say(self, text):
		text = re.sub("\s\s+", "  ", text)
		tobeencoded = ToBeEncoded(text, self.encoding)
		self.frame.np.queue.put(slskmessages.SayChatroom(self.room, tobeencoded))
		
	def NowPlayingThread(self):
		self.frame.now.DisplayNowPlaying(None, test=0, callback=self.Say)

	def UserJoinedRoom(self, username, userdata):
		if username in self.users:
			return
		# Add to completion list, and completion drop-down
		if self.frame.np.config.sections["words"]["tab"]:
			if username not in self.clist:
				self.clist.append(username)
				if self.frame.np.config.sections["words"]["dropdown"]:
					self.ChatEntry.get_completion().get_model().append([username])
		if username not in self.frame.np.config.sections["server"]["ignorelist"] and not self.frame.UserIpIsIgnored(username):
			AppendLine(self.RoomLog, _("%s joined the room") % username, self.tag_log)
		img = self.frame.GetStatusImage(userdata.status)
		flag = userdata.country
		if flag is not None:
			flag = "flag_"+flag
			self.frame.flag_users[username] = flag
		else:
			flag = self.frame.GetUserFlag(username)
		hspeed = HumanSpeed(userdata.avgspeed)
		hfiles = Humanize(userdata.files)
		self.users[username] = self.usersmodel.append([img, self.frame.GetFlagImage(flag), username, hspeed, hfiles, userdata.status, userdata.avgspeed, userdata.files, flag])
		self.getUserTag(username)

		self.CountUsers()
		
	def UserLeftRoom(self, username):
		if username not in self.users:
			return
		# Remove from completion list, and completion drop-down
		if self.frame.np.config.sections["words"]["tab"]:
			if username in self.clist and username not in [i[0] for i in self.frame.userlist.userlist]:
				self.clist.remove(username)
				if self.frame.np.config.sections["words"]["dropdown"]:
					liststore = self.ChatEntry.get_completion().get_model()
					iter = liststore.get_iter_root()
					while iter is not None:
						name = liststore.get_value(iter, 0)
						if name == username:
							liststore.remove(iter)
							break
						iter = liststore.iter_next(iter)
		if username not in self.frame.np.config.sections["server"]["ignorelist"] and not self.frame.UserIpIsIgnored(username):
			AppendLine(self.RoomLog, _("%s left the room") % username, self.tag_log)
		self.usersmodel.remove(self.users[username])
		del self.users[username]
		self.getUserTag(username)
		self.CountUsers()
		
	def CountUsers(self):
		numusers = len(self.users.keys())
		if numusers > 1:
			self.LabelPeople.show()
			self.LabelPeople.set_text(_("%i people in room") % numusers)
		elif numusers == 1:
			self.LabelPeople.show()
			self.LabelPeople.set_text(_("You are alone"))
		else:
			self.LabelPeople.hide()
		if self.room in self.roomsctrl.rooms:
			iter = self.roomsctrl.roomsmodel.get_iter_first()
			while iter:
				if self.roomsctrl.roomsmodel.get_value(iter, 0) == self.room:
					self.roomsctrl.roomsmodel.set(iter, 1, numusers)
					break
				iter = self.roomsctrl.roomsmodel.iter_next(iter)
		else:
			self.roomsctrl.roomsmodel.append([self.room, numusers, 0])
			self.roomsctrl.rooms.append(self.room)




	def UserColumnDraw(self, column, cellrenderer, model, iter):
		user = self.usersmodel.get_value(iter, 2)
		if self.room in self.roomsctrl.PrivateRooms:
			if user == self.roomsctrl.PrivateRooms[self.room]["owner"]:
				cellrenderer.set_property("underline", pango.UNDERLINE_SINGLE)
				cellrenderer.set_property("weight", pango.WEIGHT_BOLD)
			elif user in (self.roomsctrl.PrivateRooms[self.room]["operators"]):
				cellrenderer.set_property("weight", pango.WEIGHT_BOLD)
				cellrenderer.set_property("underline", pango.UNDERLINE_NONE)
			else:
				cellrenderer.set_property("weight", pango.WEIGHT_NORMAL)
				cellrenderer.set_property("underline", pango.UNDERLINE_NONE)
		else:
				cellrenderer.set_property("weight", pango.WEIGHT_NORMAL)
				cellrenderer.set_property("underline", pango.UNDERLINE_NONE)

		self.frame.CellDataFunc(column, cellrenderer, model, iter)

	def GetUserHeirarchy(self, user):
		if user not in self.users:
			return
		self.usersmodel.set(self.users[user], 3, HumanSpeed(avgspeed), 4, Humanize(files), 6, avgspeed, 7, files)

	def GetUserStats(self, user, avgspeed, files):
		if user not in self.users:
			return
		self.usersmodel.set(self.users[user], 3, HumanSpeed(avgspeed), 4, Humanize(files), 6, avgspeed, 7, files)
		
	def GetUserStatus(self, user, status):
		if user not in self.users:
			return
		img = self.frame.GetStatusImage(status)
		if img == self.usersmodel.get_value(self.users[user], 0):
			return
		if status == 1:
			action = _("%s has gone away")
		else:
			action = _("%s has returned")
		if user not in self.frame.np.config.sections["server"]["ignorelist"] and not self.frame.UserIpIsIgnored(user):
			AppendLine(self.RoomLog, action % user, self.tag_log)
		if user in self.tag_users.keys():
			color = self.getUserStatusColor(status)
			self.changecolour(self.tag_users[user], color)
		self.usersmodel.set(self.users[user], 0, img, 5, status)

	def SetUserFlag(self, user, flag):
		if user not in self.users:
			return

		self.usersmodel.set(self.users[user], 1, self.frame.GetFlagImage(flag), 8, flag)

	def makecolour(self, buffer, colour, username=None):
		colour = self.frame.np.config.sections["ui"][colour]
		font = self.frame.np.config.sections["ui"]["chatfont"]
		
		if colour:
			tag = buffer.create_tag(foreground = colour, font=font)
		else:
			tag = buffer.create_tag( font=font)
		if username is not None:
			usernamestyle = self.frame.np.config.sections["ui"]["usernamestyle"]
			
			if usernamestyle == "bold":
				tag.set_property("weight", pango.WEIGHT_BOLD)
			else:
				tag.set_property("weight", pango.WEIGHT_NORMAL)
			if usernamestyle == "italic":
				tag.set_property("style", pango.STYLE_ITALIC)
			else:
				tag.set_property("style", pango.STYLE_NORMAL)
			if usernamestyle == "underline":
				tag.set_property("underline", pango.UNDERLINE_SINGLE)
			else:
				tag.set_property("underline", pango.UNDERLINE_NONE)
				
			tag.connect("event", self.UserNameEvent, username)
			tag.last_event_type = -1
		return tag
		
	def UserNameEvent(self, tag, widget, event, iter, user):

		if tag.last_event_type == gtk.gdk.BUTTON_PRESS and event.type == gtk.gdk.BUTTON_RELEASE and event.button in (1, 2):
			#items = self.popup_menu.get_children()
			# Chat, Userlists use the normal popup system
			self.popup_menu.editing = True
			self.popup_menu.set_user(user)
			me = (self.popup_menu.user == None or self.popup_menu.user == self.frame.np.config.sections["server"]["login"])
			

			#self.Menu_SendMessage
			#self.Menu_ShowIPaddress
			#self.Menu_GetUserInfo
			#self.Menu_BrowseUser
			#self.Menu_GivePrivileges

			self.Menu_AddToList.set_active(user in [i[0] for i in self.frame.np.config.sections["server"]["userlist"]])
			self.Menu_BanUser.set_active(user in self.frame.np.config.sections["server"]["banlist"])
			self.Menu_IgnoreUser.set_active(user in self.frame.np.config.sections["server"]["ignorelist"])
			self.Menu_BlockUser.set_active(self.frame.UserIpIsBlocked(user))
			self.Menu_BlockUser.set_sensitive(not me)
			self.Menu_IgnoreIP.set_active(self.frame.UserIpIsIgnored(user))
			self.Menu_IgnoreIP.set_sensitive(not me) 
			#self.Menu_SearchUser
			self.Menu_PrivateRooms.set_sensitive(not me)

			self.popup_menu.editing = False
			self.popup_menu.popup(None, None, None, event.button, event.time)
		tag.last_event_type = event.type
		
	def UpdateColours(self):
		self.frame.ChangeListFont(self.UserList, self.frame.np.config.sections["ui"]["listfont"])
		map = self.ChatScroll.get_style().copy()
		self.backupcolor = map.text[gtk.STATE_NORMAL]
		buffer = self.ChatScroll.get_buffer()
		self.tag_remote = self.makecolour(buffer, "chatremote")
		self.tag_local = self.makecolour(buffer, "chatlocal")
		self.tag_me = self.makecolour(buffer, "chatme")
		self.tag_hilite = self.makecolour(buffer, "chathilite")
		self.tag_users = {}
		for user in self.tag_users:
			self.getUserTag(user)
	
		logbuffer = self.RoomLog.get_buffer()
		self.tag_log = self.makecolour(logbuffer, "chatremote")
		
		self.frame.SetTextBG(self.ChatScroll)
		self.frame.SetTextBG(self.RoomLog)
		self.frame.SetTextBG(self.UserList)
		
		self.frame.SetTextBG(self.ChatEntry)
		self.frame.SetTextBG(self.AutoJoin)
		self.frame.SetTextBG(self.Log)
		self.frame.SetTextBG(self.Ticker.entry)
		
		
	def getUserStatusColor(self, status):
		if status == 1:
			color = "useraway"
		elif status == 2:
			color = "useronline"
		else:
			color = "useroffline"
		if not self.frame.np.config.sections["ui"]["showaway"] and color == "useraway":
			color = "useronline"
		return color
		
	def changecolour(self, tag, colour):
		if colour in self.frame.np.config.sections["ui"]:
			color = self.frame.np.config.sections["ui"][colour]
		else:
			color = ""
		font = self.frame.np.config.sections["ui"]["chatfont"]
		
		if color == "":
			color = self.backupcolor
		else:
			color = gtk.gdk.color_parse(color)
		tag.set_property("foreground-gdk", color)
		tag.set_property("font", font)
		# Hotspots
		if colour in ["useraway", "useronline", "useroffline"]:
			usernamestyle = self.frame.np.config.sections["ui"]["usernamestyle"]
			if usernamestyle == "bold":
				tag.set_property("weight", pango.WEIGHT_BOLD)
			else:
				tag.set_property("weight", pango.WEIGHT_NORMAL)
			if usernamestyle == "italic":
				tag.set_property("style", pango.STYLE_ITALIC)
			else:
				tag.set_property("style", pango.STYLE_NORMAL)
			if usernamestyle == "underline":
				tag.set_property("underline", pango.UNDERLINE_SINGLE)
			else:
				tag.set_property("underline", pango.UNDERLINE_NONE)
		
			
	def ChangeColours(self):
		
		map = self.ChatScroll.get_style().copy()
		self.backupcolor = map.text[gtk.STATE_NORMAL]
			
		self.changecolour(self.tag_remote, "chatremote")
		self.changecolour(self.tag_local, "chatlocal")
		self.changecolour(self.tag_me, "chatme")
		self.changecolour(self.tag_hilite, "chathilite")
		self.changecolour(self.tag_log, "chatremote")

		for user in self.tag_users:
			self.getUserTag(user)

		self.frame.SetTextBG(self.ChatScroll)
		self.frame.SetTextBG(self.RoomLog)
		self.frame.SetTextBG(self.UserList)
		self.frame.SetTextBG(self.ChatEntry)
		self.frame.SetTextBG(self.AutoJoin)
		self.frame.SetTextBG(self.Log)
		self.frame.SetTextBG(self.Ticker.entry)
		self.frame.ChangeListFont(self.UserList, self.frame.np.config.sections["ui"]["listfont"])
				
	def OnLeave(self, widget = None):
		if self.leaving:
			return
		self.Leave.set_sensitive(False)
		self.leaving = 1
		config = self.frame.np.config.sections
		if self.room in config["columns"]["chatrooms"]:
			del config["columns"]["chatrooms"][self.room]
		if not self.meta:
			self.frame.np.queue.put(slskmessages.LeaveRoom(self.room))
		else:
			if self.room == 'Public ':
				self.frame.np.queue.put(slskmessages.LeavePublicRoom())
				self.roomsctrl.LeaveRoom(slskmessages.LeaveRoom(self.room)) # Faking protocol msg
			else:
				print "Unknown meta chatroom closed."
		self.frame.pluginhandler.LeaveChatroomNotification(self.room)
	def saveColumns(self):
		columns = []
		for column in self.UserList.get_columns():
			columns.append(column.get_visible())
		self.frame.np.config.sections["columns"]["chatrooms"][self.room] = columns
		
		
	def ConnClose(self):
		AppendLine(self.ChatScroll, _("--- disconnected ---"), self.tag_hilite)
		self.usersmodel.clear()
		self.UserList.set_sensitive(False)
		self.users.clear()
		self.CountUsers()
		config = self.frame.np.config.sections
		if not self.AutoJoin.get_active() and self.room in config["columns"]["chatrooms"]:
			del config["columns"]["chatrooms"][self.room]
			
		for tag in self.tag_users.values():
			self.changecolour(tag, "useroffline")
		self.Ticker.set_ticker({})
	def Rejoined(self, users):
		# Update user list with an inexpensive sorting function
		self.usersmodel.set_default_sort_func(lambda *args: -1)
		self.usersmodel.set_sort_column_id(-1, gtk.SORT_ASCENDING)
		for user in users.keys():
			if user in self.users:
				self.usersmodel.remove(self.users[user])
			img = self.frame.GetStatusImage(users[user].status)
			flag = users[user].country
			if flag is not None:
				flag = "flag_"+flag
				self.frame.flag_users[user] = flag
			else:
				flag = self.frame.GetUserFlag(user)
			hspeed = HumanSpeed(users[user].avgspeed)
			hfiles = Humanize(users[user].files)
			iter = self.usersmodel.append([img, self.frame.GetFlagImage(flag), user, hspeed, hfiles, users[user].status, users[user].avgspeed, users[user].files, flag])
			self.users[user] = iter
			self.roomsctrl.GetUserAddress(user)
		self.UserList.set_sensitive(True)
		# Reinitialize sorting after loop is complet
		self.usersmodel.set_sort_column_id(2, gtk.SORT_ASCENDING)
		self.usersmodel.set_default_sort_func(None)
		# Spit this line into chat log
		AppendLine(self.ChatScroll, _("--- reconnected ---"), self.tag_hilite)
		# Update user count
		self.CountUsers()
		# Build completion list
		self.GetCompletionList(clist=self.roomsctrl.clist)
		# Update all username tags in chat log
		for user in self.tag_users:
			self.getUserTag(user)



	def OnAutojoin(self, widget):
		autojoin = self.frame.np.config.sections["server"]["autojoin"]
		if not widget.get_active():
			if self.room in autojoin:
				autojoin.remove(self.room)
		else:
			if not self.room in autojoin:
				autojoin.append(self.room)
		self.frame.np.config.writeConfiguration()
		

	def GetCompletionList(self, ix=0, text="", clist=[]):
	
		completion = self.ChatEntry.get_completion()
		liststore = completion.get_model()
		liststore.clear()
		self.clist = []
		config = self.frame.np.config.sections["words"]
		completion.set_popup_single_match(not config["onematch"])
		completion.set_minimum_key_length(config["characters"])
		
		if not config["tab"]:
			return
		
		if config["roomusers"]:
			clist += list(self.users.keys())

		# no duplicates
		def _combilower(x):
			try:
				return str.lower(x)
			except:
				return unicode.lower(x)
		clist = list(set(clist))
		clist.sort(key=_combilower)
		completion.set_popup_completion(False)
		if config["dropdown"]:
			for word in clist:
				liststore.append([word])
			completion.set_popup_completion(True)
		self.clist = clist
		
		
	def OnKeyPress(self, widget, event):
		if event.keyval == gtk.gdk.keyval_from_name("Prior"):
			scrolled = self.ChatScroll.get_parent()
			adj = scrolled.get_vadjustment()
			adj.set_value(adj.value - adj.page_increment)
		elif event.keyval == gtk.gdk.keyval_from_name("Next"):
			scrolled = self.ChatScroll.get_parent()
			adj = scrolled.get_vadjustment()
			max = adj.upper - adj.page_size
			new = adj.value + adj.page_increment
			if new > max:
				new = max
			adj.set_value(new)
		# ISO_Left_Tab normally corresponds with shift+tab
		if event.keyval not in (gtk.gdk.keyval_from_name("Tab"), gtk.gdk.keyval_from_name("ISO_Left_Tab")):
			if event.keyval not in (gtk.gdk.keyval_from_name("Shift_L"), gtk.gdk.keyval_from_name("Shift_R")):
				self.midwaycompletion = False
			return False
		config = self.frame.np.config.sections["words"]
		if not config["tab"]:
			return False
		# "Hello there Miss<tab> how are you doing"
		# "0  3  6  9  12 15      18 21 24 27 30 33
		#   1  4  7  10 13      16 19 22 25 28 31
		#    2  5  8  11 14      17 20 23 26 29 32
		#
		# ix = 16
		# text = Miss
		# preix = 12
		ix = widget.get_position()
		text = widget.get_text()[:ix].split(" ")[-1]
		preix = ix - len(text)

		if not config["cycle"]:
			completion, single = GetCompletion(text, self.clist)
			if completion:
				if single:
					if ix == len(text) and text[:1] != "/":
						completion += ": "
				widget.delete_text(preix, ix)
				widget.insert_text(completion, preix)
				widget.set_position(preix + len(completion))
		else:
			if not self.midwaycompletion:
				self.completions['completions'] = GetCompletions(text, self.clist)
				if self.completions['completions']:
					self.midwaycompletion = True
					self.completions['currentindex'] = -1
					currentnick = text
			else:
				currentnick = self.completions['completions'][self.completions['currentindex']]
			if self.midwaycompletion:
				widget.delete_text(ix - len(currentnick), ix)
				direction = 1 # Forward cycle
				if event.keyval == gtk.gdk.keyval_from_name("ISO_Left_Tab"):
					direction = -1 # Backward cycle
				self.completions['currentindex'] = (self.completions['currentindex'] + direction) % len(self.completions['completions'])

				newnick = self.completions['completions'][self.completions['currentindex']]
				widget.insert_text(newnick, preix)
				widget.set_position(preix + len(newnick))
		widget.emit_stop_by_name("key_press_event")
		return True

	def OnTooltip(self, widget, x, y, keyboard_mode, tooltip):
		return showCountryTooltip(widget, x, y, tooltip, 8)
	def OnLogToggled(self, widget):
		if not widget.get_active():
			if self.logfile is not None:
				self.logfile.close()
				self.logfile = None
			if self.room in self.frame.np.config.sections["logging"]["rooms"]:
				self.frame.np.config.sections["logging"]["rooms"].remove(self.room)
		elif widget.get_active():
			if self.room not in self.frame.np.config.sections["logging"]["rooms"]:
				self.frame.np.config.sections["logging"]["rooms"].append(self.room)
		
	def OnEncodingChanged(self, widget):
		try:
			# PyGTK 2.6
			encoding = self.Encoding.get_active_text()
		except:
			# PyGTK 2.4
			iter = self.Encoding.get_active_iter()
			encoding_model = self.Encoding.get_model()
			encoding = encoding_model.get_value(iter, 0)
		if encoding != self.encoding:
			self.encoding = encoding
			SaveEncoding(self.frame.np, "roomencoding", self.room, self.encoding)
	
	def OnPopupChatRoomMenu(self, widget, event):
		if event.button != 3:
			return False
		widget.emit_stop_by_name("button-press-event")
		self.chatpopmenu.popup(None, None, None, event.button, event.time)
		return True
	
	def OnPopupRoomLogMenu(self, widget, event):
		if event.button != 3:
			return False
		widget.emit_stop_by_name("button-press-event")
		self.logpopupmenu.popup(None, None, None, event.button, event.time)
		return True
	
	def OnCopyAllRoomLog(self, widget):
		start, end = self.RoomLog.get_buffer().get_bounds()
		log = self.RoomLog.get_buffer().get_text(start, end)
		self.frame.clip.set_text(log)
		
	def OnCopyRoomLog(self, widget):
		bound = self.RoomLog.get_buffer().get_selection_bounds()
		if bound is not None and len(bound) == 2:
			start, end = bound
			log = self.RoomLog.get_buffer().get_text(start, end)
			self.frame.clip.set_text(log)
			
	def OnCopyChatLog(self, widget):
		bound = self.ChatScroll.get_buffer().get_selection_bounds()
		if bound is not None and len(bound) == 2:
			start, end = bound
			log = self.ChatScroll.get_buffer().get_text(start, end)
			self.frame.clip.set_text(log)
		
	def OnCopyAllChatLog(self, widget):
		start, end = self.ChatScroll.get_buffer().get_bounds()
		log = self.ChatScroll.get_buffer().get_text(start, end)
		self.frame.clip.set_text(log)
		
	def OnClearChatLog(self, widget):
		self.ChatScroll.get_buffer().set_text("")
		self.lines = []

	def OnClearRoomLog(self, widget):
		self.RoomLog.get_buffer().set_text("")

	def OnTickerFocus(self, widget, event):
		if widget.is_focus():
			self.Ticker.disable()
		else:
			self.Ticker.enable()
			
	def GetTabParent(self, page):
		if self.frame.ChatNotebook.is_tab_detached(page):
			return self.Main.get_parent().get_parent()
		return self.frame.MainWindow
		
	def OnTickerClicked(self, widget, event):
		if event.button != 1 or event.type != gtk.gdk._2BUTTON_PRESS:
			return False
		config = self.frame.np.config.sections
		if config["server"]["login"] in self.Ticker.messages:
			old = self.Ticker.messages[config["server"]["login"]]
		else:
			old = ""
		t, result = TickDialog(self.GetTabParent(self.Main), old)
		if not result is None:
			if t == 1:
				if not result:
					if self.room in config["ticker"]["rooms"]:
						del config["ticker"]["rooms"][self.room]
				else:
					config["ticker"]["rooms"][self.room] = result
				self.frame.np.config.writeConfiguration()
			elif t == 2:
				if self.room in config["ticker"]["rooms"]:
					del config["ticker"]["rooms"][self.room]
				config["ticker"]["default"] = result
				self.frame.np.config.writeConfiguration()
			self.frame.np.queue.put(slskmessages.RoomTickerSet(self.room, ToBeEncoded(result, self.encoding)))
		return True

	def ShowTicker(self, visible):
		if visible:
			self.Ticker.enable()
			self.Ticker.show()
		else:
			self.Ticker.disable()
			self.Ticker.hide()

class ChatRooms(IconNotebook):
	def __init__(self, frame):
		self.frame = frame
		ui = self.frame.np.config.sections["ui"]
		IconNotebook.__init__(self, self.frame.images, ui["labelrooms"], ui["tabclosers"], ui["tab_icons"], ui["tab_reorderable"])
		self.roomsctrl = RoomsControl(frame, self)
		
		
		self.popup_enable()
		self.set_tab_pos(self.frame.getTabPosition(self.frame.np.config.sections["ui"]["tabrooms"]))
		
		
	def TabPopup(self, room):
		if room not in self.roomsctrl.joinedrooms:
			return
		popup = PopupMenu(self.frame)
		popup.setup(
			("#" + _("Detach this tab"), self.roomsctrl.joinedrooms[room].Detach, gtk.STOCK_REDO),
			("#" + _("Leave this room"), self.roomsctrl.joinedrooms[room].OnLeave, gtk.STOCK_CLOSE),
		)
		popup.set_user(room)
		
	
		return popup
		
	def on_tab_click(self, widget, event, child):
		if event.type == gtk.gdk.BUTTON_PRESS:
			n = self.page_num(child)
			page = self.get_nth_page(n)
			room = [room for room, tab in self.roomsctrl.joinedrooms.items() if tab.Main is page][0]
			if event.button == 2:
				self.roomsctrl.joinedrooms[room].OnLeave(widget)
				return True
			if event.button == 3:
				menu = self.TabPopup(room)
				menu.popup(None, None, None, event.button, event.time)
				return True
			return False
		return False
	
	def ConnClose(self):
		self.roomsctrl.ConnClose()
