2011-01-01 13:27:07 +00:00
# Copyright 2010-2011 Le Coz Florent <louiz@louiz.org>
2010-09-14 02:11:07 +00:00
#
# This file is part of Poezio.
#
# Poezio 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, version 3 of the License.
#
# Poezio 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 Poezio. If not, see <http://www.gnu.org/licenses/>.
"""
2010-11-22 01:39:37 +00:00
a Tab object is a way to organize various Windows ( see windows . py )
2010-09-14 02:11:07 +00:00
around the screen at once .
2010-11-15 11:59:09 +00:00
A tab is then composed of multiple Buffer .
Each Tab object has different refresh ( ) and resize ( ) methods , defining how its
Buffer are displayed , resized , etc
2010-09-14 02:11:07 +00:00
"""
MIN_WIDTH = 50
2010-09-14 02:24:04 +00:00
MIN_HEIGHT = 16
2010-09-14 02:11:07 +00:00
2010-11-24 05:41:06 +00:00
from gettext import ( bindtextdomain , textdomain , bind_textdomain_codeset ,
gettext as _ )
2010-11-11 03:39:39 +00:00
import logging
log = logging . getLogger ( __name__ )
2010-11-22 01:39:37 +00:00
import windows
2010-09-14 02:11:07 +00:00
import theme
2010-10-17 05:14:22 +00:00
import curses
2010-11-11 05:24:43 +00:00
import difflib
2010-11-24 05:41:06 +00:00
import shlex
2010-12-31 11:23:56 +00:00
import text_buffer
2010-11-11 05:24:43 +00:00
from sleekxmpp . xmlstream . stanzabase import JID
2010-10-27 22:49:52 +00:00
from config import config
2010-10-31 18:57:48 +00:00
from roster import RosterGroup , roster
2010-10-17 17:27:07 +00:00
from contact import Contact , Resource
2010-11-24 05:41:06 +00:00
import multiuserchat as muc
2010-09-14 02:11:07 +00:00
class Tab ( object ) :
number = 0
2010-11-19 16:27:20 +00:00
def __init__ ( self , core ) :
2010-11-09 20:37:39 +00:00
self . core = core # a pointer to core, to access its attributes (ugly?)
2010-09-14 02:11:07 +00:00
self . nb = Tab . number
Tab . number + = 1
2010-11-19 16:27:20 +00:00
self . size = ( self . height , self . width ) = self . core . stdscr . getmaxyx ( )
2010-09-14 02:11:07 +00:00
if self . height < MIN_HEIGHT or self . width < MIN_WIDTH :
self . visible = False
else :
self . visible = True
2010-11-22 02:00:03 +00:00
self . key_func = { } # each tab should add their keys in there
# and use them in on_input
2010-11-24 05:41:06 +00:00
self . commands = { } # and their own commands
2010-09-14 02:11:07 +00:00
2010-11-25 03:04:03 +00:00
def complete_commands ( self , the_input ) :
"""
Does command completion on the specified input for both global and tab - specific
commands .
This should be called from the completion method ( on tab , for example ) , passing
the input where completion is to be made .
It can completion the command name itself or an argument of the command .
Returns True if a completion was made , False else .
"""
txt = the_input . get_text ( )
# check if this is a command
if txt . startswith ( ' / ' ) and not txt . startswith ( ' // ' ) :
# check if we are in the middle of the command name
if len ( txt . split ( ) ) > 1 or \
( txt . endswith ( ' ' ) and not the_input . last_completion ) :
command_name = txt . split ( ) [ 0 ] [ 1 : ]
if command_name in self . core . commands :
command = self . core . commands [ command_name ]
elif command_name in self . commands :
command = self . commands [ command_name ]
else : # Unknown command, cannot complete
return False
if command [ 2 ] is None :
return False # There's no completion functio
else :
return command [ 2 ] ( the_input )
else :
# complete the command's name
words = [ ' / %s ' % ( name ) for name in list ( self . core . commands . keys ( ) ) ] + \
[ ' / %s ' % ( name ) for name in list ( self . commands . keys ( ) ) ]
the_input . auto_completion ( words , ' ' )
return True
return False
2010-09-14 02:11:07 +00:00
2011-01-11 05:43:31 +00:00
def on_enter ( self , provided_text = None ) :
"""
Execute the command in the input and return False if
the input didn ' t contain a command
"""
txt = provided_text or self . input . key_enter ( )
if txt . startswith ( ' / ' ) and not txt . startswith ( ' // ' ) and \
not txt . startswith ( ' /me ' ) :
command = txt . strip ( ) . split ( ) [ 0 ] [ 1 : ]
arg = txt [ 2 + len ( command ) : ] # jump the '/' and the ' '
if command in self . core . commands : # check global commands
self . core . commands [ command ] [ 0 ] ( arg )
elif command in self . commands : # check tab-specific commands
self . commands [ command ] [ 0 ] ( arg )
else :
self . core . information ( _ ( " Unknown command ( %s ) " ) % ( command ) , _ ( ' Error ' ) )
return True
else :
return False
2010-11-19 16:27:20 +00:00
def resize ( self ) :
self . size = ( self . height , self . width ) = self . core . stdscr . getmaxyx ( )
2010-09-14 02:11:07 +00:00
if self . height < MIN_HEIGHT or self . width < MIN_WIDTH :
self . visible = False
else :
self . visible = True
2010-11-25 03:04:03 +00:00
def refresh ( self , tabs , informations , roster ) :
"""
Called on each screen refresh ( when something has changed )
"""
raise NotImplementedError
2010-09-14 02:11:07 +00:00
def get_color_state ( self ) :
"""
returns the color that should be used in the GlobalInfoBar
"""
2010-12-26 20:51:14 +00:00
return theme . COLOR_TAB_NORMAL
2010-09-14 02:11:07 +00:00
def set_color_state ( self , color ) :
"""
set the color state
"""
2010-12-26 20:51:14 +00:00
pass
2010-09-14 02:11:07 +00:00
def get_name ( self ) :
"""
get the name of the tab
"""
2010-12-26 20:51:14 +00:00
return self . __class__ . __name__
2010-09-14 02:11:07 +00:00
2010-12-15 17:05:52 +00:00
def get_text_window ( self ) :
"""
Returns the principal TextWin window , if there ' s one
"""
return None
2010-09-14 02:11:07 +00:00
def on_input ( self , key ) :
2010-12-07 16:20:30 +00:00
pass
2010-09-14 02:11:07 +00:00
def on_lose_focus ( self ) :
"""
called when this tab loses the focus .
"""
2010-12-07 16:20:30 +00:00
pass
2010-09-14 02:11:07 +00:00
def on_gain_focus ( self ) :
"""
called when this tab gains the focus .
"""
2010-12-07 16:20:30 +00:00
pass
2010-09-14 02:11:07 +00:00
def add_message ( self ) :
"""
Adds a message in the tab .
If the tab cannot add a message in itself ( for example
FormTab , where text is not intented to be appened ) , it returns False .
If the tab can , it returns True
"""
2010-12-07 16:20:30 +00:00
return False
2010-09-14 02:11:07 +00:00
def on_scroll_down ( self ) :
"""
Defines what happens when we scrol down
"""
2010-12-07 16:20:30 +00:00
pass
2010-09-14 02:11:07 +00:00
def on_scroll_up ( self ) :
"""
Defines what happens when we scrol down
"""
2010-12-07 16:20:30 +00:00
pass
2010-09-14 02:11:07 +00:00
2010-11-19 16:27:20 +00:00
def on_info_win_size_changed ( self ) :
2010-09-14 02:11:07 +00:00
"""
Called when the window with the informations is resized
"""
2010-12-07 16:20:30 +00:00
pass
2010-09-14 02:11:07 +00:00
2010-10-17 05:14:22 +00:00
def just_before_refresh ( self ) :
"""
Method called just before the screen refresh .
Particularly useful to move the cursor at the
correct position .
"""
2010-12-07 16:20:30 +00:00
pass
2010-10-17 05:14:22 +00:00
2010-11-11 03:39:39 +00:00
def on_close ( self ) :
"""
Called when the tab is to be closed
"""
2010-12-07 16:20:30 +00:00
pass
2010-11-11 03:39:39 +00:00
2010-11-22 01:39:37 +00:00
class ChatTab ( Tab ) :
"""
2010-11-22 02:00:03 +00:00
A tab containing a chat of any type .
Just use this class instead of Tab if the tab needs a recent - words completion
Also , \n , ^ J and ^ M are already bound to on_enter
2010-11-24 05:41:06 +00:00
And also , add the / say command
2010-11-22 01:39:37 +00:00
"""
2010-11-22 02:00:03 +00:00
def __init__ ( self , core , room ) :
Tab . __init__ ( self , core )
self . _room = room
self . key_func [ ' M-/ ' ] = self . last_words_completion
self . key_func [ ' ^J ' ] = self . on_enter
self . key_func [ ' ^M ' ] = self . on_enter
self . key_func [ ' \n ' ] = self . on_enter
2010-11-24 05:41:06 +00:00
self . commands [ ' say ' ] = ( self . command_say ,
_ ( """ Usage: /say <message> \n Say: Just send the message.
2010-11-25 03:04:03 +00:00
Useful if you want your message to begin with a ' / ' """ ), None)
2010-11-22 02:00:03 +00:00
def last_words_completion ( self ) :
"""
Complete the input with words recently said
"""
# build the list of the recent words
char_we_dont_want = [ ' , ' , ' ( ' , ' ) ' , ' . ' , ' " ' , ' \' ' , ' ' , # The last one is nbsp
' ’ ' , ' “ ' , ' ” ' , ' : ' , ' ; ' , ' [ ' , ' ] ' , ' { ' , ' } ' ]
words = list ( )
for msg in self . _room . messages [ : - 40 : - 1 ] :
if not msg :
continue
2010-11-27 02:41:45 +00:00
txt = msg . txt
2010-11-22 02:00:03 +00:00
for char in char_we_dont_want :
2010-11-27 02:41:45 +00:00
txt = txt . replace ( char , ' ' )
for word in txt . split ( ) :
2010-11-22 02:00:03 +00:00
if len ( word ) > = 4 and word not in words :
words . append ( word )
2010-11-25 03:04:03 +00:00
self . input . auto_completion ( words , ' ' )
2010-11-22 02:00:03 +00:00
def on_enter ( self ) :
2011-01-11 18:50:47 +00:00
txt = self . input . key_enter ( )
2011-01-11 18:56:40 +00:00
if not Tab . on_enter ( self , txt ) :
2010-11-24 05:41:06 +00:00
self . command_say ( txt )
def command_say ( self , line ) :
2010-11-22 02:00:03 +00:00
raise NotImplementedError
2010-12-31 13:05:06 +00:00
class InfoTab ( ChatTab ) :
"""
The information tab , used to display global informations
when using a anonymous account
"""
def __init__ ( self , core ) :
Tab . __init__ ( self , core )
self . tab_win = windows . GlobalInfoBar ( )
self . info_win = windows . TextWin ( )
self . core . information_buffer . add_window ( self . info_win )
self . input = windows . Input ( )
self . name = " Info "
self . color_state = theme . COLOR_TAB_NORMAL
self . key_func [ ' ^J ' ] = self . on_enter
self . key_func [ ' ^M ' ] = self . on_enter
self . key_func [ ' \n ' ] = self . on_enter
self . key_func [ ' ^I ' ] = self . completion
self . key_func [ ' M-i ' ] = self . completion
self . resize ( )
def resize ( self ) :
Tab . resize ( self )
self . tab_win . resize ( 1 , self . width , self . height - 2 , 0 , self . core . stdscr )
self . info_win . resize ( self . height - 2 , self . width , 0 , 0 , self . core . stdscr )
self . input . resize ( 1 , self . width , self . height - 1 , 0 , self . core . stdscr )
def refresh ( self , tabs , informations , _ ) :
if not self . visible :
return
self . info_win . refresh ( informations )
self . tab_win . refresh ( tabs , tabs [ 0 ] )
self . input . refresh ( )
def completion ( self ) :
self . complete_commands ( self . input )
def get_name ( self ) :
return self . name
def get_color_state ( self ) :
return self . color_state
def set_color_state ( self , color ) :
return
def on_input ( self , key ) :
if key in self . key_func :
self . key_func [ key ] ( )
return False
self . input . do_command ( key )
return False
def on_lose_focus ( self ) :
self . color_state = theme . COLOR_TAB_NORMAL
def on_gain_focus ( self ) :
self . color_state = theme . COLOR_TAB_CURRENT
curses . curs_set ( 1 )
def on_scroll_up ( self ) :
pass
def on_scroll_down ( self ) :
pass
def on_info_win_size_changed ( self ) :
return
def just_before_refresh ( self ) :
return
def on_close ( self ) :
return
2010-11-22 02:00:03 +00:00
class MucTab ( ChatTab ) :
2010-09-14 02:11:07 +00:00
"""
The tab containing a multi - user - chat room .
It contains an userlist , an input , a topic , an information and a chat zone
"""
2010-11-19 16:27:20 +00:00
def __init__ ( self , core , room ) :
2010-11-22 02:00:03 +00:00
ChatTab . __init__ ( self , core , room )
2010-11-22 02:25:15 +00:00
self . topic_win = windows . Topic ( )
self . text_win = windows . TextWin ( )
2010-12-15 15:40:43 +00:00
room . add_window ( self . text_win )
2010-11-22 02:25:15 +00:00
self . v_separator = windows . VerticalSeparator ( )
self . user_win = windows . UserList ( )
self . info_header = windows . MucInfoWin ( )
self . info_win = windows . TextWin ( )
2010-12-15 15:40:43 +00:00
self . core . information_buffer . add_window ( self . info_win )
2010-11-22 02:25:15 +00:00
self . tab_win = windows . GlobalInfoBar ( )
self . input = windows . MessageInput ( )
2010-11-24 05:41:06 +00:00
self . ignores = [ ] # set of Users
# keys
2010-11-22 02:00:03 +00:00
self . key_func [ ' ^I ' ] = self . completion
self . key_func [ ' M-i ' ] = self . completion
2011-01-01 15:37:35 +00:00
self . key_func [ ' M-u ' ] = self . scroll_user_list_down
self . key_func [ ' M-y ' ] = self . scroll_user_list_up
2010-11-24 05:41:06 +00:00
# commands
2010-11-25 03:04:03 +00:00
self . commands [ ' ignore ' ] = ( self . command_ignore , _ ( " Usage: /ignore <nickname> \n Ignore: Ignore a specified nickname. " ) , None )
self . commands [ ' unignore ' ] = ( self . command_unignore , _ ( " Usage: /unignore <nickname> \n Unignore: Remove the specified nickname from the ignore list. " ) , None )
self . commands [ ' kick ' ] = ( self . command_kick , _ ( " Usage: /kick <nick> [reason] \n Kick: Kick the user with the specified nickname. You also can give an optional reason. " ) , None )
self . commands [ ' topic ' ] = ( self . command_topic , _ ( " Usage: /topic <subject> \n Topic: Change the subject of the room " ) , None )
self . commands [ ' query ' ] = ( self . command_query , _ ( ' Usage: /query <nick> [message] \n Query: Open a private conversation with <nick>. This nick has to be present in the room you \' re currently in. If you specified a message after the nickname, it will immediately be sent to this user ' ) , None )
self . commands [ ' part ' ] = ( self . command_part , _ ( " Usage: /part [message] \n Part: disconnect from a room. You can specify an optional message. " ) , None )
self . commands [ ' nick ' ] = ( self . command_nick , _ ( " Usage: /nick <nickname> \n Nick: Change your nickname in the current room " ) , None )
self . commands [ ' recolor ' ] = ( self . command_recolor , _ ( ' Usage: /recolor \n Recolor: Re-assign a color to all participants of the current room, based on the last time they talked. Use this if the participants currently talking have too many identical colors. ' ) , None )
2011-01-04 03:05:49 +00:00
self . commands [ ' cycle ' ] = ( self . command_cycle , _ ( ' Usage: /cycle [message] \n Cycle: Leaves the current room and rejoin it immediately ' ) , None )
2010-11-22 02:25:15 +00:00
self . resize ( )
2010-09-14 02:11:07 +00:00
2011-01-01 15:37:35 +00:00
def scroll_user_list_up ( self ) :
self . user_win . scroll_up ( )
self . core . refresh_window ( )
def scroll_user_list_down ( self ) :
self . user_win . scroll_down ( )
self . core . refresh_window ( )
2011-01-04 03:05:49 +00:00
def command_cycle ( self , arg ) :
if self . get_room ( ) . joined :
2011-01-04 03:08:44 +00:00
muc . leave_groupchat ( self . core . xmpp , self . get_name ( ) , self . get_room ( ) . own_nick , arg )
2011-01-04 03:05:49 +00:00
self . get_room ( ) . joined = False
2011-01-04 03:36:04 +00:00
self . core . command_join ( ' / ' , " 0 " )
2011-01-04 03:05:49 +00:00
2010-11-24 05:41:06 +00:00
def command_recolor ( self , arg ) :
"""
Re - assign color to the participants of the room
"""
room = self . get_room ( )
i = 0
compare_users = lambda x : x . last_talked
users = list ( room . users )
# search our own user, to remove it from the room
for user in users :
if user . nick == room . own_nick :
users . remove ( user )
nb_color = len ( theme . LIST_COLOR_NICKNAMES )
for user in sorted ( users , key = compare_users , reverse = True ) :
user . color = theme . LIST_COLOR_NICKNAMES [ i % nb_color ]
2011-01-04 03:36:04 +00:00
i + = 1
2010-12-15 17:05:52 +00:00
self . text_win . rebuild_everything ( self . get_room ( ) )
2010-11-24 05:41:06 +00:00
self . core . refresh_window ( )
def command_nick ( self , arg ) :
"""
/ nick < nickname >
"""
try :
args = shlex . split ( arg )
except ValueError as error :
return self . core . information ( str ( error ) , _ ( " Error " ) )
if len ( args ) != 1 :
return
nick = args [ 0 ]
room = self . get_room ( )
if not room . joined :
return
muc . change_nick ( self . core . xmpp , room . name , nick )
def command_part ( self , arg ) :
"""
/ part [ msg ]
"""
args = arg . split ( )
reason = None
room = self . get_room ( )
if len ( args ) :
msg = ' ' . join ( args )
else :
msg = None
if self . get_room ( ) . joined :
muc . leave_groupchat ( self . core . xmpp , room . name , room . own_nick , arg )
self . core . close_tab ( )
def command_query ( self , arg ) :
"""
/ query < nick > [ message ]
"""
try :
args = shlex . split ( arg )
except ValueError as error :
return self . core . information ( str ( error ) , _ ( " Error " ) )
if len ( args ) < 1 :
return
nick = args [ 0 ]
room = self . get_room ( )
r = None
for user in room . users :
if user . nick == nick :
r = self . core . open_private_window ( room . name , user . nick )
if r and len ( args ) > 1 :
msg = arg [ len ( nick ) + 1 : ]
muc . send_private_message ( self . core . xmpp , r . name , msg )
self . core . add_message_to_text_buffer ( r , msg , None , r . own_nick )
def command_topic ( self , arg ) :
"""
/ topic [ new topic ]
"""
if not arg . strip ( ) :
self . core . add_message_to_text_buffer ( self . get_room ( ) ,
_ ( " The subject of the room is: %s " ) % self . get_room ( ) . topic )
return
subject = arg
muc . change_subject ( self . core . xmpp , self . get_room ( ) . name , subject )
def command_kick ( self , arg ) :
"""
/ kick < nick > [ reason ]
"""
try :
args = shlex . split ( arg )
except ValueError as error :
return self . core . information ( str ( error ) , _ ( " Error " ) )
if len ( args ) < 1 :
self . core . command_help ( ' kick ' )
return
nick = args [ 0 ]
if len ( args ) > = 2 :
reason = ' ' . join ( args [ 1 : ] )
else :
reason = ' '
if not self . get_room ( ) . joined :
return
res = muc . eject_user ( self . core . xmpp , self . get_name ( ) , nick , reason )
if res [ ' type ' ] == ' error ' :
self . core . room_error ( res , self . get_name ( ) )
def command_say ( self , line ) :
muc . send_groupchat_message ( self . core . xmpp , self . get_name ( ) , line )
def command_ignore ( self , arg ) :
"""
/ ignore < nick >
"""
try :
args = shlex . split ( arg )
except ValueError as error :
return self . core . information ( str ( error ) , _ ( " Error " ) )
if len ( args ) != 1 :
self . core . command_help ( ' ignore ' )
return
nick = args [ 0 ]
user = self . _room . get_user_by_name ( nick )
if not user :
self . core . information ( _ ( ' %s is not in the room ' ) % nick )
elif user in self . ignores :
self . core . information ( _ ( ' %s is already ignored ' ) % nick )
else :
self . ignores . append ( user )
self . core . information ( _ ( " %s is now ignored " ) % nick , ' info ' )
def command_unignore ( self , arg ) :
"""
/ unignore < nick >
"""
try :
args = shlex . split ( arg )
except ValueError as error :
return self . core . information ( str ( error ) , _ ( " Error " ) )
if len ( args ) != 1 :
self . core . command_help ( ' unignore ' )
return
nick = args [ 0 ]
user = self . _room . get_user_by_name ( nick )
if not user :
self . core . information ( _ ( ' %s is not in the room ' ) % nick )
elif user not in self . ignores :
self . core . information ( _ ( ' %s is not ignored ' ) % nick )
else :
self . ignores . remove ( user )
self . core . information ( _ ( ' %s is now unignored ' ) % nick )
2010-11-19 16:27:20 +00:00
def resize ( self ) :
2010-09-14 02:11:07 +00:00
"""
Resize the whole window . i . e . all its sub - windows
"""
2010-11-19 16:27:20 +00:00
Tab . resize ( self )
2010-09-14 02:11:07 +00:00
text_width = ( self . width / / 10 ) * 9
2010-11-22 02:39:56 +00:00
self . topic_win . resize ( 1 , self . width , 0 , 0 , self . core . stdscr )
self . text_win . resize ( self . height - 4 - self . core . information_win_size , text_width , 1 , 0 , self . core . stdscr )
2010-12-15 15:40:43 +00:00
self . text_win . rebuild_everything ( self . _room )
2010-11-22 02:39:56 +00:00
self . v_separator . resize ( self . height - 3 , 1 , 1 , 9 * ( self . width / / 10 ) , self . core . stdscr )
self . user_win . resize ( self . height - 3 , self . width - text_width - 1 , 1 , text_width + 1 , self . core . stdscr )
self . info_header . resize ( 1 , ( self . width / / 10 ) * 9 , self . height - 3 - self . core . information_win_size , 0 , self . core . stdscr )
2010-12-15 15:40:43 +00:00
self . info_win . resize ( self . core . information_win_size , ( self . width / / 10 ) * 9 , self . height - 2 - self . core . information_win_size , 0 , self . core . stdscr , self . core . information_buffer )
2010-11-22 02:39:56 +00:00
self . tab_win . resize ( 1 , self . width , self . height - 2 , 0 , self . core . stdscr )
self . input . resize ( 1 , self . width , self . height - 1 , 0 , self . core . stdscr )
2010-09-14 02:11:07 +00:00
2010-09-26 18:01:38 +00:00
def refresh ( self , tabs , informations , _ ) :
2010-11-22 02:39:56 +00:00
if not self . visible :
return
2010-09-14 02:11:07 +00:00
self . topic_win . refresh ( self . _room . topic )
self . text_win . refresh ( self . _room )
self . v_separator . refresh ( )
self . user_win . refresh ( self . _room . users )
2010-12-15 15:40:43 +00:00
self . info_header . refresh ( self . _room , self . text_win )
2010-09-14 02:11:07 +00:00
self . tab_win . refresh ( tabs , tabs [ 0 ] )
2010-12-15 15:40:43 +00:00
self . info_win . refresh ( informations )
2010-09-14 02:11:07 +00:00
self . input . refresh ( )
def on_input ( self , key ) :
2010-11-22 02:00:03 +00:00
if key in self . key_func :
self . key_func [ key ] ( )
2010-11-15 13:16:30 +00:00
return False
self . input . do_command ( key )
return False
2010-09-14 02:11:07 +00:00
def completion ( self ) :
"""
Called when Tab is pressed , complete the nickname in the input
"""
2010-11-25 03:04:03 +00:00
if self . complete_commands ( self . input ) :
return
2010-12-15 19:32:51 +00:00
# If we are not completing a command or a command's argument, complete a nick
2010-09-14 02:11:07 +00:00
compare_users = lambda x : x . last_talked
2010-12-15 19:32:51 +00:00
word_list = [ user . nick for user in sorted ( self . _room . users , key = compare_users , reverse = True ) \
if user . nick != self . _room . own_nick ]
2010-11-25 03:04:03 +00:00
after = config . get ( ' after_completion ' , ' , ' ) + " "
if ' ' not in self . input . get_text ( ) or ( self . input . last_completion and \
self . input . get_text ( ) [ : - len ( after ) ] == self . input . last_completion ) :
add_after = after
else :
add_after = ' '
self . input . auto_completion ( word_list , add_after )
2010-09-14 02:11:07 +00:00
def get_color_state ( self ) :
return self . _room . color_state
def set_color_state ( self , color ) :
self . _room . set_color_state ( color )
def get_name ( self ) :
return self . _room . name
2010-12-15 17:05:52 +00:00
def get_text_window ( self ) :
return self . text_win
2010-09-14 02:11:07 +00:00
def get_room ( self ) :
return self . _room
def on_lose_focus ( self ) :
self . _room . set_color_state ( theme . COLOR_TAB_NORMAL )
2010-12-15 16:10:53 +00:00
self . text_win . remove_line_separator ( )
self . text_win . add_line_separator ( )
2010-09-14 02:11:07 +00:00
def on_gain_focus ( self ) :
self . _room . set_color_state ( theme . COLOR_TAB_CURRENT )
2011-01-10 17:59:34 +00:00
if self . text_win . built_lines and self . text_win . built_lines [ - 1 ] is None :
2011-01-09 02:23:04 +00:00
self . text_win . remove_line_separator ( )
2010-10-17 05:14:22 +00:00
curses . curs_set ( 1 )
2010-09-14 02:11:07 +00:00
def on_scroll_up ( self ) :
2010-12-15 15:40:43 +00:00
self . text_win . scroll_up ( self . text_win . height - 1 )
2010-09-14 02:11:07 +00:00
def on_scroll_down ( self ) :
2010-12-15 15:40:43 +00:00
self . text_win . scroll_down ( self . text_win . height - 1 )
2010-09-14 02:11:07 +00:00
2010-11-19 16:27:20 +00:00
def on_info_win_size_changed ( self ) :
2010-09-14 02:11:07 +00:00
text_width = ( self . width / / 10 ) * 9
2010-11-22 02:39:56 +00:00
self . text_win . resize ( self . height - 4 - self . core . information_win_size , text_width , 1 , 0 , self . core . stdscr )
self . info_header . resize ( 1 , ( self . width / / 10 ) * 9 , self . height - 3 - self . core . information_win_size , 0 , self . core . stdscr )
self . info_win . resize ( self . core . information_win_size , ( self . width / / 10 ) * 9 , self . height - 2 - self . core . information_win_size , 0 , self . core . stdscr )
2010-09-14 02:11:07 +00:00
2010-10-17 05:14:22 +00:00
def just_before_refresh ( self ) :
2010-11-11 20:44:14 +00:00
return
2010-10-17 05:14:22 +00:00
2010-11-11 03:39:39 +00:00
def on_close ( self ) :
return
2010-11-22 02:00:03 +00:00
class PrivateTab ( ChatTab ) :
2010-09-14 02:11:07 +00:00
"""
The tab containg a private conversation ( someone from a MUC )
"""
2010-11-19 16:27:20 +00:00
def __init__ ( self , core , room ) :
2010-11-22 02:00:03 +00:00
ChatTab . __init__ ( self , core , room )
2010-11-22 02:25:15 +00:00
self . text_win = windows . TextWin ( )
2010-12-15 15:40:43 +00:00
room . add_window ( self . text_win )
2010-11-22 02:25:15 +00:00
self . info_header = windows . PrivateInfoWin ( )
self . info_win = windows . TextWin ( )
2010-12-15 15:40:43 +00:00
self . core . information_buffer . add_window ( self . info_win )
2010-11-22 02:25:15 +00:00
self . tab_win = windows . GlobalInfoBar ( )
self . input = windows . MessageInput ( )
2010-11-25 03:04:03 +00:00
# keys
self . key_func [ ' ^I ' ] = self . completion
self . key_func [ ' M-i ' ] = self . completion
# commands
self . commands [ ' unquery ' ] = ( self . command_unquery , _ ( " Usage: /unquery \n Unquery: close the tab " ) , None )
self . commands [ ' part ' ] = ( self . command_unquery , _ ( " Usage: /part \ Part: close the tab " ) , None )
2010-11-22 02:25:15 +00:00
self . resize ( )
2010-11-19 16:27:20 +00:00
2010-11-25 03:04:03 +00:00
def completion ( self ) :
self . complete_commands ( self . input )
2010-11-24 05:41:06 +00:00
def command_say ( self , line ) :
muc . send_private_message ( self . core . xmpp , self . get_name ( ) , line )
self . core . add_message_to_text_buffer ( self . get_room ( ) , line , None , self . get_room ( ) . own_nick )
def command_unquery ( self , arg ) :
"""
/ unquery
"""
self . core . close_tab ( )
2010-11-19 16:27:20 +00:00
def resize ( self ) :
Tab . resize ( self )
2010-11-22 02:39:56 +00:00
self . text_win . resize ( self . height - 3 - self . core . information_win_size , self . width , 0 , 0 , self . core . stdscr )
2010-12-15 15:40:43 +00:00
self . text_win . rebuild_everything ( self . _room )
2010-11-22 02:39:56 +00:00
self . info_header . resize ( 1 , self . width , self . height - 3 - self . core . information_win_size , 0 , self . core . stdscr )
2010-12-15 15:40:43 +00:00
self . info_win . resize ( self . core . information_win_size , self . width , self . height - 2 - self . core . information_win_size , 0 , self . core . stdscr , self . core . information_buffer )
2010-11-22 02:39:56 +00:00
self . tab_win . resize ( 1 , self . width , self . height - 2 , 0 , self . core . stdscr )
self . input . resize ( 1 , self . width , self . height - 1 , 0 , self . core . stdscr )
2010-09-14 02:11:07 +00:00
2010-09-26 18:01:38 +00:00
def refresh ( self , tabs , informations , _ ) :
2010-11-22 02:39:56 +00:00
if not self . visible :
return
2010-09-14 02:11:07 +00:00
self . text_win . refresh ( self . _room )
2010-12-15 15:40:43 +00:00
self . info_header . refresh ( self . _room , self . text_win )
2010-09-14 02:11:07 +00:00
self . info_win . refresh ( informations )
self . tab_win . refresh ( tabs , tabs [ 0 ] )
self . input . refresh ( )
def get_color_state ( self ) :
if self . _room . color_state == theme . COLOR_TAB_NORMAL or \
self . _room . color_state == theme . COLOR_TAB_CURRENT :
return self . _room . color_state
return theme . COLOR_TAB_PRIVATE
def set_color_state ( self , color ) :
self . _room . color_state = color
def get_name ( self ) :
return self . _room . name
def on_input ( self , key ) :
2010-11-22 02:00:03 +00:00
if key in self . key_func :
self . key_func [ key ] ( )
2010-11-15 13:16:30 +00:00
return False
2010-11-23 13:46:19 +00:00
self . input . do_command ( key )
return False
2010-09-14 02:11:07 +00:00
def on_lose_focus ( self ) :
self . _room . set_color_state ( theme . COLOR_TAB_NORMAL )
2010-12-15 16:10:53 +00:00
self . text_win . remove_line_separator ( )
self . text_win . add_line_separator ( )
2010-09-14 02:11:07 +00:00
def on_gain_focus ( self ) :
self . _room . set_color_state ( theme . COLOR_TAB_CURRENT )
2010-11-10 21:15:08 +00:00
curses . curs_set ( 1 )
2010-09-14 02:11:07 +00:00
def on_scroll_up ( self ) :
2010-12-15 15:40:43 +00:00
self . text_win . scroll_up ( self . text_win . height - 1 )
2010-09-14 02:11:07 +00:00
def on_scroll_down ( self ) :
2010-12-15 15:40:43 +00:00
self . text_win . scroll_down ( self . text_win . height - 1 )
2010-09-14 02:11:07 +00:00
2010-11-19 16:27:20 +00:00
def on_info_win_size_changed ( self ) :
2010-11-22 02:39:56 +00:00
self . text_win . resize ( self . height - 3 - self . core . information_win_size , self . width , 0 , 0 , self . core . stdscr )
self . info_header . resize ( 1 , self . width , self . height - 3 - self . core . information_win_size , 0 , self . core . stdscr )
2010-12-15 15:40:43 +00:00
self . info_win . resize ( self . core . information_win_size , self . width , self . height - 2 - self . core . information_win_size , 0 , self . core . stdscr , None )
2010-09-14 02:11:07 +00:00
def get_room ( self ) :
return self . _room
2010-09-15 19:05:20 +00:00
2010-12-15 17:05:52 +00:00
def get_text_window ( self ) :
return self . text_win
2010-10-17 05:14:22 +00:00
def just_before_refresh ( self ) :
return
2010-11-11 03:39:39 +00:00
def on_close ( self ) :
return
2010-09-15 19:05:20 +00:00
class RosterInfoTab ( Tab ) :
"""
2010-09-26 18:01:38 +00:00
A tab , splitted in two , containing the roster and infos
2010-09-15 19:05:20 +00:00
"""
2010-11-19 16:27:20 +00:00
def __init__ ( self , core ) :
Tab . __init__ ( self , core )
2010-09-15 19:05:20 +00:00
self . name = " Roster "
2010-11-22 02:25:15 +00:00
self . v_separator = windows . VerticalSeparator ( )
self . tab_win = windows . GlobalInfoBar ( )
self . info_win = windows . TextWin ( )
2010-12-15 15:40:43 +00:00
self . core . information_buffer . add_window ( self . info_win )
2010-11-22 02:25:15 +00:00
self . roster_win = windows . RosterWin ( )
self . contact_info_win = windows . ContactInfoWin ( )
self . default_help_message = windows . HelpText ( " Enter commands with “/”. “o”: toggle offline show " )
2010-11-11 20:44:14 +00:00
self . input = self . default_help_message
2010-09-15 19:05:20 +00:00
self . set_color_state ( theme . COLOR_TAB_NORMAL )
2010-11-25 03:04:03 +00:00
self . key_func [ ' ^I ' ] = self . completion
self . key_func [ ' M-i ' ] = self . completion
self . key_func [ " ^J " ] = self . on_enter
self . key_func [ " ^M " ] = self . on_enter
self . key_func [ ' ' ] = self . on_space
self . key_func [ " / " ] = self . on_slash
self . key_func [ " KEY_UP " ] = self . move_cursor_up
self . key_func [ " KEY_DOWN " ] = self . move_cursor_down
self . key_func [ " o " ] = self . toggle_offline_show
2011-01-10 17:54:21 +00:00
self . key_func [ " s " ] = self . start_search
self . key_func [ " S " ] = self . start_search_slow
2011-01-11 02:41:06 +00:00
self . commands [ ' deny ' ] = ( self . command_deny , _ ( " Usage: /deny [jid] \n Deny: Use this command to remove and deny your presence to the provided JID (or the selected contact in your roster), who is asking you to be in his/here roster " ) , self . completion_deny )
2011-01-11 05:43:31 +00:00
self . commands [ ' accept ' ] = ( self . command_accept , _ ( " Usage: /accpet [jid] \n Accept: Use this command to authorize the provided JID (or the selected contact in your roster), to see your presence, and to ask to subscribe to it (mutual presence subscription). " ) , self . completion_deny )
2010-11-22 02:25:15 +00:00
self . resize ( )
2010-09-15 19:05:20 +00:00
2010-11-19 16:27:20 +00:00
def resize ( self ) :
Tab . resize ( self )
2010-09-15 19:05:20 +00:00
roster_width = self . width / / 2
info_width = self . width - roster_width - 1
2010-11-22 02:39:56 +00:00
self . v_separator . resize ( self . height - 2 , 1 , 0 , roster_width , self . core . stdscr )
self . tab_win . resize ( 1 , self . width , self . height - 2 , 0 , self . core . stdscr )
2011-01-11 01:49:43 +00:00
self . info_win . resize ( self . height - 2 - 4 , info_width , 0 , roster_width + 1 , self . core . stdscr , self . core . information_buffer )
self . roster_win . resize ( self . height - 2 , roster_width , 0 , 0 , self . core . stdscr )
self . contact_info_win . resize ( 4 , info_width , self . height - 2 - 4 , roster_width + 1 , self . core . stdscr )
2010-11-22 02:39:56 +00:00
self . input . resize ( 1 , self . width , self . height - 1 , 0 , self . core . stdscr )
2010-09-15 19:05:20 +00:00
2010-11-25 03:04:03 +00:00
def completion ( self ) :
# Check if we are entering a command (with the '/' key)
if isinstance ( self . input , windows . CommandInput ) and \
not self . input . help_message :
self . complete_commands ( self . input )
2010-12-15 21:21:33 +00:00
2011-01-11 02:41:06 +00:00
def command_deny ( self , args ) :
"""
Denies a JID from our roster
"""
2011-01-11 05:43:31 +00:00
args = args . split ( )
if not args :
item = self . roster_win . selected_row
if isinstance ( item , Contact ) and item . get_ask ( ) == ' asked ' :
jid = item . get_bare_jid ( )
else :
self . core . information ( ' No subscription to deny ' )
return
else :
jid = args [ 0 ]
self . core . xmpp . sendPresence ( pto = jid , ptype = ' unsubscribed ' )
if self . core . xmpp . update_roster ( jid , subscription = ' remove ' ) :
roster . remove_contact ( jid )
def completion_deny ( self , the_input ) :
"""
Complete the first argument from the list of the
contact with ask == ' subscribe '
"""
jids = [ contact . get_bare_jid ( ) for contact in roster . get_contacts ( ) \
if contact . get_ask ( ) == ' asked ' ]
the_input . auto_completion ( jids , ' ' )
def command_accept ( self , args ) :
"""
Accept a JID from in roster . Authorize it AND subscribe to it
"""
args = args . split ( )
if not args :
item = self . roster_win . selected_row
if isinstance ( item , Contact ) and item . get_ask ( ) == ' asked ' :
jid = item . get_bare_jid ( )
else :
self . core . information ( ' No subscription to deny ' )
return
else :
jid = args [ 0 ]
self . core . xmpp . sendPresence ( pto = jid , ptype = ' subscribed ' )
self . core . xmpp . sendPresence ( pto = jid , ptype = ' subscribe ' )
2010-09-26 18:01:38 +00:00
def refresh ( self , tabs , informations , roster ) :
2010-11-22 02:39:56 +00:00
if not self . visible :
return
2010-10-17 05:14:22 +00:00
self . v_separator . refresh ( )
2010-09-26 18:01:38 +00:00
self . roster_win . refresh ( roster )
2010-10-04 00:27:40 +00:00
self . contact_info_win . refresh ( self . roster_win . get_selected_row ( ) )
2010-12-15 15:40:43 +00:00
# self.core.global_information_win.refresh(informations)
2010-09-15 19:05:20 +00:00
self . info_win . refresh ( informations )
self . tab_win . refresh ( tabs , tabs [ 0 ] )
self . input . refresh ( )
def get_name ( self ) :
return self . name
def get_color_state ( self ) :
return self . _color_state
def set_color_state ( self , color ) :
self . _color_state = color
def on_input ( self , key ) :
2010-11-11 20:44:14 +00:00
res = self . input . do_command ( key )
if res :
2010-11-23 15:25:18 +00:00
return True
2010-11-25 03:04:03 +00:00
if key in self . key_func :
return self . key_func [ key ] ( )
2010-10-27 22:49:52 +00:00
def toggle_offline_show ( self ) :
"""
Show or hide offline contacts
"""
option = ' roster_show_offline '
if config . get ( option , ' false ' ) == ' false ' :
config . set_and_save ( option , ' true ' )
else :
config . set_and_save ( option , ' false ' )
return True
2010-10-31 18:57:48 +00:00
2010-10-27 22:49:52 +00:00
def on_slash ( self ) :
"""
' / ' is pressed , we enter " input mode "
"""
curses . curs_set ( 1 )
2010-11-22 02:48:24 +00:00
self . input = windows . CommandInput ( " " , self . reset_help_message , self . execute_slash_command )
self . input . resize ( 1 , self . width , self . height - 1 , 0 , self . core . stdscr )
2010-11-11 20:44:14 +00:00
self . input . do_command ( " / " ) # we add the slash
def reset_help_message ( self , _ = None ) :
curses . curs_set ( 0 )
self . input = self . default_help_message
return True
def execute_slash_command ( self , txt ) :
if txt . startswith ( ' / ' ) :
2011-01-11 05:43:31 +00:00
Tab . on_enter ( self , txt )
2010-11-11 20:44:14 +00:00
return self . reset_help_message ( )
2010-09-15 19:05:20 +00:00
def on_lose_focus ( self ) :
self . _color_state = theme . COLOR_TAB_NORMAL
def on_gain_focus ( self ) :
self . _color_state = theme . COLOR_TAB_CURRENT
2010-12-15 21:21:33 +00:00
if isinstance ( self . input , windows . HelpText ) :
curses . curs_set ( 0 )
else :
curses . curs_set ( 1 )
2010-09-15 19:05:20 +00:00
def add_message ( self ) :
return False
2010-10-27 22:49:52 +00:00
def move_cursor_down ( self ) :
2010-09-26 18:01:38 +00:00
self . roster_win . move_cursor_down ( )
2010-10-27 22:49:52 +00:00
return True
2010-09-15 19:05:20 +00:00
2010-10-27 22:49:52 +00:00
def move_cursor_up ( self ) :
2010-09-26 18:01:38 +00:00
self . roster_win . move_cursor_up ( )
2010-10-27 22:49:52 +00:00
return True
def on_scroll_down ( self ) :
# Scroll info win
pass
def on_scroll_up ( self ) :
# Scroll info down
pass
2010-09-15 19:05:20 +00:00
2010-11-19 16:27:20 +00:00
def on_info_win_size_changed ( self ) :
2010-09-26 18:01:38 +00:00
pass
2010-10-17 17:27:07 +00:00
def on_space ( self ) :
selected_row = self . roster_win . get_selected_row ( )
if isinstance ( selected_row , RosterGroup ) or \
isinstance ( selected_row , Contact ) :
selected_row . toggle_folded ( )
return True
2010-10-31 18:57:48 +00:00
2010-09-26 18:01:38 +00:00
def on_enter ( self ) :
2010-09-27 01:40:34 +00:00
selected_row = self . roster_win . get_selected_row ( )
2010-11-11 20:44:14 +00:00
self . core . on_roster_enter_key ( selected_row )
2010-09-27 01:40:34 +00:00
return selected_row
2010-09-26 18:01:38 +00:00
2010-10-31 18:57:48 +00:00
def start_search ( self ) :
"""
Start the search . The input should appear with a short instruction
in it .
"""
curses . curs_set ( 1 )
2010-11-23 15:25:18 +00:00
self . input = windows . CommandInput ( " [Search] " , self . on_search_terminate , self . on_search_terminate , self . set_roster_filter )
self . input . resize ( 1 , self . width , self . height - 1 , 0 , self . core . stdscr )
2010-10-31 18:57:48 +00:00
return True
2011-01-10 17:54:21 +00:00
def start_search_slow ( self ) :
curses . curs_set ( 1 )
self . input = windows . CommandInput ( " [Search] " , self . on_search_terminate , self . on_search_terminate , self . set_roster_filter_slow )
self . input . resize ( 1 , self . width , self . height - 1 , 0 , self . core . stdscr )
return True
def set_roster_filter_slow ( self , txt ) :
roster . _contact_filter = ( jid_and_name_match_slow , txt )
self . roster_win . refresh ( roster )
return False
2010-11-11 20:44:14 +00:00
def set_roster_filter ( self , txt ) :
roster . _contact_filter = ( jid_and_name_match , txt )
2010-11-23 15:25:18 +00:00
self . roster_win . refresh ( roster )
return False
2010-11-11 20:44:14 +00:00
2010-10-31 18:57:48 +00:00
def on_search_terminate ( self , txt ) :
curses . curs_set ( 0 )
roster . _contact_filter = None
2010-11-11 20:44:14 +00:00
self . reset_help_message ( )
2010-12-17 18:58:07 +00:00
return False
2010-10-31 18:57:48 +00:00
2010-10-17 05:14:22 +00:00
def just_before_refresh ( self ) :
return
2010-11-11 03:39:39 +00:00
def on_close ( self ) :
return
2010-11-22 02:00:03 +00:00
class ConversationTab ( ChatTab ) :
2010-09-26 18:01:38 +00:00
"""
2010-12-31 10:52:15 +00:00
The tab containg a normal conversation ( not from a MUC )
2010-09-26 18:01:38 +00:00
"""
2010-12-31 10:52:15 +00:00
def __init__ ( self , core , jid ) :
2010-12-31 11:23:56 +00:00
txt_buff = text_buffer . TextBuffer ( )
ChatTab . __init__ ( self , core , txt_buff )
2010-11-10 21:15:08 +00:00
self . color_state = theme . COLOR_TAB_NORMAL
self . _name = jid # a conversation tab is linked to one specific full jid OR bare jid
2010-11-22 02:25:15 +00:00
self . text_win = windows . TextWin ( )
2010-12-31 11:23:56 +00:00
txt_buff . add_window ( self . text_win )
2010-11-22 02:25:15 +00:00
self . upper_bar = windows . ConversationStatusMessageWin ( )
self . info_header = windows . ConversationInfoWin ( )
self . info_win = windows . TextWin ( )
2010-12-15 15:40:43 +00:00
self . core . information_buffer . add_window ( self . info_win )
2010-11-22 02:25:15 +00:00
self . tab_win = windows . GlobalInfoBar ( )
self . input = windows . MessageInput ( )
2010-11-25 03:04:03 +00:00
# keys
self . key_func [ ' ^I ' ] = self . completion
self . key_func [ ' M-i ' ] = self . completion
# commands
self . commands [ ' unquery ' ] = ( self . command_unquery , _ ( " Usage: /unquery \n Unquery: close the tab " ) , None )
self . commands [ ' part ' ] = ( self . command_unquery , _ ( " Usage: /part \ Part: close the tab " ) , None )
2010-11-22 02:25:15 +00:00
self . resize ( )
2010-11-19 16:27:20 +00:00
2010-11-25 03:04:03 +00:00
def completion ( self ) :
self . complete_commands ( self . input )
2010-11-24 05:41:06 +00:00
def command_say ( self , line ) :
muc . send_private_message ( self . core . xmpp , self . get_name ( ) , line )
self . core . add_message_to_text_buffer ( self . get_room ( ) , line , None , self . core . own_nick )
def command_unquery ( self , arg ) :
self . core . close_tab ( )
2010-11-19 16:27:20 +00:00
def resize ( self ) :
Tab . resize ( self )
2010-12-15 17:26:34 +00:00
self . text_win . resize ( self . height - 4 - self . core . information_win_size , self . width , 1 , 0 , self . core . stdscr )
2010-12-15 15:40:43 +00:00
self . text_win . rebuild_everything ( self . _room )
2010-11-22 02:39:56 +00:00
self . upper_bar . resize ( 1 , self . width , 0 , 0 , self . core . stdscr )
self . info_header . resize ( 1 , self . width , self . height - 3 - self . core . information_win_size , 0 , self . core . stdscr )
2010-12-15 15:40:43 +00:00
self . info_win . resize ( self . core . information_win_size , self . width , self . height - 2 - self . core . information_win_size , 0 , self . core . stdscr , self . core . information_buffer )
2010-11-22 02:39:56 +00:00
self . tab_win . resize ( 1 , self . width , self . height - 2 , 0 , self . core . stdscr )
self . input . resize ( 1 , self . width , self . height - 1 , 0 , self . core . stdscr )
2010-09-26 18:01:38 +00:00
2010-09-27 01:40:34 +00:00
def refresh ( self , tabs , informations , roster ) :
2010-11-22 02:39:56 +00:00
if not self . visible :
return
2010-11-22 02:00:03 +00:00
self . text_win . refresh ( self . _room )
2010-11-10 21:15:08 +00:00
self . upper_bar . refresh ( self . get_name ( ) , roster . get_contact_by_jid ( self . get_name ( ) ) )
2010-12-15 17:15:46 +00:00
self . info_header . refresh ( self . get_name ( ) , roster . get_contact_by_jid ( self . get_name ( ) ) , self . _room , self . text_win )
2010-09-26 18:01:38 +00:00
self . info_win . refresh ( informations )
self . tab_win . refresh ( tabs , tabs [ 0 ] )
self . input . refresh ( )
def get_color_state ( self ) :
2010-11-10 21:15:08 +00:00
if self . color_state == theme . COLOR_TAB_NORMAL or \
self . color_state == theme . COLOR_TAB_CURRENT :
return self . color_state
2010-09-26 18:01:38 +00:00
return theme . COLOR_TAB_PRIVATE
def set_color_state ( self , color ) :
2010-11-10 21:15:08 +00:00
self . color_state = color
2010-09-26 18:01:38 +00:00
def get_name ( self ) :
2010-11-10 21:15:08 +00:00
return self . _name
2010-09-26 18:01:38 +00:00
def on_input ( self , key ) :
2010-11-22 02:00:03 +00:00
if key in self . key_func :
self . key_func [ key ] ( )
2010-11-15 13:16:30 +00:00
return False
2010-11-19 16:27:20 +00:00
self . input . do_command ( key )
2010-11-23 13:46:19 +00:00
return False
2010-09-26 18:01:38 +00:00
def on_lose_focus ( self ) :
2010-11-10 21:15:08 +00:00
self . set_color_state ( theme . COLOR_TAB_NORMAL )
2010-12-15 16:10:53 +00:00
self . text_win . remove_line_separator ( )
self . text_win . add_line_separator ( )
2010-09-26 18:01:38 +00:00
def on_gain_focus ( self ) :
2010-11-10 21:15:08 +00:00
self . set_color_state ( theme . COLOR_TAB_CURRENT )
curses . curs_set ( 1 )
2010-09-26 18:01:38 +00:00
def on_scroll_up ( self ) :
2010-12-15 15:40:43 +00:00
self . text_win . scroll_up ( self . text_win . height - 1 )
2010-09-26 18:01:38 +00:00
def on_scroll_down ( self ) :
2010-12-15 15:40:43 +00:00
self . text_win . scroll_down ( self . text_win . height - 1 )
2010-09-26 18:01:38 +00:00
2010-11-19 16:27:20 +00:00
def on_info_win_size_changed ( self ) :
2010-11-22 02:39:56 +00:00
self . text_win . resize ( self . height - 3 - self . core . information_win_size , self . width , 0 , 0 , self . core . stdscr )
self . info_header . resize ( 1 , self . width , self . height - 3 - self . core . information_win_size , 0 , self . core . stdscr )
self . info_win . resize ( self . core . information_win_size , self . width , self . height - 2 - self . core . information_win_size , 0 , self . core . stdscr )
2010-09-26 18:01:38 +00:00
def get_room ( self ) :
2010-11-22 02:00:03 +00:00
return self . _room
2010-10-17 05:14:22 +00:00
2010-12-15 17:05:52 +00:00
def get_text_window ( self ) :
return self . text_win
2010-10-17 05:14:22 +00:00
def just_before_refresh ( self ) :
return
2010-10-31 18:57:48 +00:00
2010-11-11 03:39:39 +00:00
def on_close ( self ) :
return
2010-12-07 16:20:30 +00:00
class MucListTab ( Tab ) :
"""
A tab listing rooms from a specific server , displaying various information ,
scrollable , and letting the user join them , etc
"""
def __init__ ( self , core , server ) :
Tab . __init__ ( self , core )
self . _color_state = theme . COLOR_TAB_NORMAL
self . name = server
self . upper_message = windows . Topic ( )
2011-01-02 15:50:01 +00:00
self . upper_message . set_message ( ' Chatroom list on server %s (Loading) ' % self . name )
2010-12-07 16:20:30 +00:00
columns = ( ' node-part ' , ' name ' , ' users ' )
self . list_header = windows . ColumnHeaderWin ( columns )
self . listview = windows . ListWin ( columns )
self . tab_win = windows . GlobalInfoBar ( )
2010-12-21 05:43:57 +00:00
self . default_help_message = windows . HelpText ( " “j”: join room. " )
2010-12-07 16:20:30 +00:00
self . input = self . default_help_message
self . key_func [ " KEY_DOWN " ] = self . listview . move_cursor_down
self . key_func [ " KEY_UP " ] = self . listview . move_cursor_up
self . key_func [ " / " ] = self . on_slash
self . key_func [ ' j ' ] = self . join_selected
self . key_func [ ' J ' ] = self . join_selected_no_focus
2010-12-07 19:45:08 +00:00
self . key_func [ ' ^J ' ] = self . join_selected
self . key_func [ ' ^M ' ] = self . join_selected
2010-12-07 16:20:30 +00:00
self . resize ( )
def refresh ( self , tabs , informations , roster ) :
2011-01-02 15:50:01 +00:00
self . upper_message . refresh ( )
2010-12-07 16:20:30 +00:00
self . list_header . refresh ( )
self . listview . refresh ( )
self . tab_win . refresh ( tabs , tabs [ 0 ] )
self . input . refresh ( )
def resize ( self ) :
Tab . resize ( self )
self . upper_message . resize ( 1 , self . width , 0 , 0 , self . core . stdscr )
column_size = { ' node-part ' : ( self . width - 5 ) / / 4 ,
' name ' : ( self . width - 5 ) / / 4 * 3 ,
' users ' : 5 }
self . list_header . resize_columns ( column_size )
self . list_header . resize ( 1 , self . width , 1 , 0 , self . core . stdscr )
self . listview . resize_columns ( column_size )
self . listview . resize ( self . height - 4 , self . width , 2 , 0 , self . core . stdscr )
self . tab_win . resize ( 1 , self . width , self . height - 2 , 0 , self . core . stdscr )
self . input . resize ( 1 , self . width , self . height - 1 , 0 , self . core . stdscr )
def on_slash ( self ) :
"""
' / ' is pressed , activate the input
"""
curses . curs_set ( 1 )
self . input = windows . CommandInput ( " " , self . reset_help_message , self . execute_slash_command )
self . input . resize ( 1 , self . width , self . height - 1 , 0 , self . core . stdscr )
self . input . do_command ( " / " ) # we add the slash
def join_selected_no_focus ( self ) :
return
2011-01-02 15:50:01 +00:00
def set_error ( self , msg , code , body ) :
"""
If there ' s an error (retrieving the values etc)
"""
self . _error_message = _ ( ' Error: %(code)s - %(msg)s : %(body)s ' ) % { ' msg ' : msg , ' body ' : body , ' code ' : code }
self . upper_message . set_message ( self . _error_message )
self . upper_message . refresh ( )
curses . doupdate ( )
def on_muc_list_item_received ( self , iq ) :
"""
Callback called when a disco #items result is received
Used with command_list
"""
log . debug ( ' res: %s \n \n ' % iq )
if iq [ ' type ' ] == ' error ' :
self . set_error ( iq [ ' error ' ] [ ' type ' ] , iq [ ' error ' ] [ ' code ' ] , iq [ ' error ' ] [ ' text ' ] )
return
items = [ { ' node-part ' : JID ( item [ 0 ] ) . user ,
' jid ' : item [ 0 ] ,
' name ' : item [ 2 ] } for item in iq [ ' disco_items ' ] . get_items ( ) ]
self . listview . add_lines ( items )
self . upper_message . set_message ( ' Chatroom list on server %s ' % self . name )
self . upper_message . refresh ( )
curses . doupdate ( )
2010-12-07 16:20:30 +00:00
def join_selected ( self ) :
2010-12-07 19:37:30 +00:00
row = self . listview . get_selected_row ( )
if not row :
return
self . core . command_join ( row [ ' jid ' ] )
2010-12-07 16:20:30 +00:00
def reset_help_message ( self , _ = None ) :
curses . curs_set ( 0 )
self . input = self . default_help_message
return True
def execute_slash_command ( self , txt ) :
if txt . startswith ( ' / ' ) :
self . core . execute ( txt )
return self . reset_help_message ( )
2010-12-26 20:51:14 +00:00
def get_name ( self ) :
return self . name
def on_input ( self , key ) :
res = self . input . do_command ( key )
if res :
return True
if key in self . key_func :
return self . key_func [ key ] ( )
def on_lose_focus ( self ) :
self . _color_state = theme . COLOR_TAB_NORMAL
def on_gain_focus ( self ) :
self . _color_state = theme . COLOR_TAB_CURRENT
curses . curs_set ( 0 )
2010-12-07 16:20:30 +00:00
def get_color_state ( self ) :
2010-12-26 20:51:14 +00:00
return self . _color_state
2010-12-07 16:20:30 +00:00
2010-12-26 20:51:14 +00:00
class SimpleTextTab ( Tab ) :
"""
A very simple tab , with just a text displaying some
information or whatever .
For example used to display tracebacks
"""
def __init__ ( self , core , text ) :
Tab . __init__ ( self , core )
self . _color_state = theme . COLOR_TAB_NORMAL
self . text_win = windows . SimpleTextWin ( text )
self . tab_win = windows . GlobalInfoBar ( )
self . default_help_message = windows . HelpText ( " “Ctrl+q”: close " )
self . input = self . default_help_message
self . key_func [ ' ^T ' ] = self . close
self . key_func [ " / " ] = self . on_slash
self . resize ( )
2010-12-07 16:20:30 +00:00
2010-12-26 20:51:14 +00:00
def on_slash ( self ) :
"""
' / ' is pressed , activate the input
"""
curses . curs_set ( 1 )
self . input = windows . CommandInput ( " " , self . reset_help_message , self . execute_slash_command )
self . input . resize ( 1 , self . width , self . height - 1 , 0 , self . core . stdscr )
self . input . do_command ( " / " ) # we add the slash
2010-12-07 16:20:30 +00:00
def on_input ( self , key ) :
res = self . input . do_command ( key )
if res :
return True
if key in self . key_func :
return self . key_func [ key ] ( )
2010-12-26 20:51:14 +00:00
def close ( self ) :
self . core . close_tab ( )
def resize ( self ) :
self . text_win . resize ( self . height - 2 , self . width , 0 , 0 , self . core . stdscr )
self . tab_win . resize ( 1 , self . width , self . height - 2 , 0 , self . core . stdscr )
self . input . resize ( 1 , self . width , self . height - 1 , 0 , self . core . stdscr )
def refresh ( self , tabs , information , roster ) :
self . text_win . refresh ( )
self . tab_win . refresh ( tabs , tabs [ 0 ] )
self . input . refresh ( )
2010-12-07 16:20:30 +00:00
def on_lose_focus ( self ) :
self . _color_state = theme . COLOR_TAB_NORMAL
def on_gain_focus ( self ) :
self . _color_state = theme . COLOR_TAB_CURRENT
curses . curs_set ( 0 )
def get_color_state ( self ) :
return self . _color_state
2010-11-11 05:24:43 +00:00
def diffmatch ( search , string ) :
"""
Use difflib and a loop to check if search_pattern can
be ' almost ' found INSIDE a string .
' almost ' being defined by difflib
"""
l = len ( search )
ratio = 0.7
for i in range ( len ( string ) - l + 1 ) :
if difflib . SequenceMatcher ( None , search , string [ i : i + l ] ) . ratio ( ) > = ratio :
return True
return False
2010-10-31 18:57:48 +00:00
def jid_and_name_match ( contact , txt ) :
2011-01-10 17:54:21 +00:00
"""
"""
if not txt :
return True
if txt in JID ( contact . get_bare_jid ( ) ) . user :
return True
return False
def jid_and_name_match_slow ( contact , txt ) :
2010-10-31 18:57:48 +00:00
"""
A function used to know if a contact in the roster should
be shown in the roster
"""
2010-11-11 05:24:43 +00:00
ratio = 0.7
if not txt :
return True # Everything matches when search is empty
user = JID ( contact . get_bare_jid ( ) ) . user
if diffmatch ( txt , user ) :
return True
if contact . get_name ( ) and diffmatch ( txt , contact . get_name ( ) ) :
2010-10-31 18:57:48 +00:00
return True
return False