# -*- 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 .
#
# 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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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 (username, user) in users.iteritems():
img = self.frame.GetStatusImage(user.status)
flag = user.country
if flag is not None:
flag = "flag_"+flag
self.frame.flag_users[username] = flag
else:
flag = self.frame.GetUserFlag(username)
hspeed = HumanSpeed(user.avgspeed)
hfiles = Humanize(user.files)
iter = self.usersmodel.append([img, self.frame.GetFlagImage(flag), username, hspeed, hfiles, user.status, user.avgspeed, user.files, flag])
self.users[username] = iter
self.roomsctrl.GetUserAddress(username)
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:
log.add('Alias "%s" returned nothing' % alias)
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:
user = byteargs.split(" ", 1)[0]
try:
msg = args.split(" ", 1)[1]
except IndexError:
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:
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 (username, user) in users.iteritems():
if username in self.users:
self.usersmodel.remove(self.users[username])
img = self.frame.GetStatusImage(user.status)
flag = user.country
if flag is not None:
flag = "flag_"+flag
self.frame.flag_users[username] = flag
else:
flag = self.frame.GetUserFlag(username)
hspeed = HumanSpeed(user.avgspeed)
hfiles = Humanize(user.files)
myiter = self.usersmodel.append([img, self.frame.GetFlagImage(flag), username, hspeed, hfiles, user.status, user.avgspeed, user.files, flag])
self.users[username] = myiter
self.roomsctrl.GetUserAddress(username)
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 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()