diff options
author | louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13 <louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13> | 2010-12-07 16:20:30 +0000 |
---|---|---|
committer | louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13 <louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13> | 2010-12-07 16:20:30 +0000 |
commit | d837ce23811d8d201ced2bd8ee1554a21b836c2f (patch) | |
tree | 036e4ebbe492113fb0e088ba28f7eed054037de1 /src/tab.py | |
parent | 2b58f653b7fafe7017d23351b9dcc39167757772 (diff) | |
download | poezio-d837ce23811d8d201ced2bd8ee1554a21b836c2f.tar.gz poezio-d837ce23811d8d201ced2bd8ee1554a21b836c2f.tar.bz2 poezio-d837ce23811d8d201ced2bd8ee1554a21b836c2f.tar.xz poezio-d837ce23811d8d201ced2bd8ee1554a21b836c2f.zip |
/list command, can join the room with J (cannot sort, search or filter yet, and lacks some information)
Diffstat (limited to 'src/tab.py')
-rw-r--r-- | src/tab.py | 962 |
1 files changed, 0 insertions, 962 deletions
diff --git a/src/tab.py b/src/tab.py deleted file mode 100644 index 4a76fca4..00000000 --- a/src/tab.py +++ /dev/null @@ -1,962 +0,0 @@ -# Copyright 2010 Le Coz Florent <louiz@louiz.org> -# -# 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/>. - -""" -a Tab object is a way to organize various Windows (see windows.py) -around the screen at once. -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 -""" - -MIN_WIDTH = 50 -MIN_HEIGHT = 16 - -from gettext import (bindtextdomain, textdomain, bind_textdomain_codeset, - gettext as _) - -import logging -log = logging.getLogger(__name__) - -import windows -import theme -import curses -import difflib -import shlex - -from sleekxmpp.xmlstream.stanzabase import JID -from config import config -from roster import RosterGroup, roster -from contact import Contact, Resource -import multiuserchat as muc - -class Tab(object): - number = 0 - - def __init__(self, core): - self.core = core # a pointer to core, to access its attributes (ugly?) - self.nb = Tab.number - Tab.number += 1 - self.size = (self.height, self.width) = self.core.stdscr.getmaxyx() - if self.height < MIN_HEIGHT or self.width < MIN_WIDTH: - self.visible = False - else: - self.visible = True - self.key_func = {} # each tab should add their keys in there - # and use them in on_input - self.commands = {} # and their own commands - - 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 - - def resize(self): - self.size = (self.height, self.width) = self.core.stdscr.getmaxyx() - if self.height < MIN_HEIGHT or self.width < MIN_WIDTH: - self.visible = False - else: - self.visible = True - - def refresh(self, tabs, informations, roster): - """ - Called on each screen refresh (when something has changed) - """ - raise NotImplementedError - - def get_color_state(self): - """ - returns the color that should be used in the GlobalInfoBar - """ - raise NotImplementedError - - def set_color_state(self, color): - """ - set the color state - """ - raise NotImplementedError - - def get_name(self): - """ - get the name of the tab - """ - raise NotImplementedError - - def on_input(self, key): - raise NotImplementedError - - def on_lose_focus(self): - """ - called when this tab loses the focus. - """ - raise NotImplementedError - - def on_gain_focus(self): - """ - called when this tab gains the focus. - """ - raise NotImplementedError - - 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 - """ - raise NotImplementedError - - def on_scroll_down(self): - """ - Defines what happens when we scrol down - """ - raise NotImplementedError - - def on_scroll_up(self): - """ - Defines what happens when we scrol down - """ - raise NotImplementedError - - def on_info_win_size_changed(self): - """ - Called when the window with the informations is resized - """ - raise NotImplementedError - - def just_before_refresh(self): - """ - Method called just before the screen refresh. - Particularly useful to move the cursor at the - correct position. - """ - raise NotImplementedError - - def on_close(self): - """ - Called when the tab is to be closed - """ - raise NotImplementedError - -class InfoTab(Tab): - """ - The information tab, used to display global informations - when using a anonymous account - """ - def __init__(self, core, name): - Tab.__init__(self, core) - self.tab_win = windows.GlobalInfoBar() - self.text_win = windows.TextWin() - self.input = windows.Input() - self.name = name - self.color_state = theme.COLOR_TAB_NORMAL - self.resize() - - def resize(self): - Tab.resize(self) - self.tab_win.resize(1, self.width, self.height-2, 0, self.core.stdscr) - self.tab_win.resize(1, self.width, self.height-2, 0, self.core.stdscr) - self.text_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.text_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): - return - - def on_input(self, key): - return self.input.do_command(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) - - 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 - -class ChatTab(Tab): - """ - 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 - And also, add the /say command - """ - 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 - self.commands['say'] = (self.command_say, - _("""Usage: /say <message>\nSay: Just send the message. - Useful if you want your message to begin with a '/'"""), None) - - 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 - txt = msg.txt - for char in char_we_dont_want: - txt = txt.replace(char, ' ') - for word in txt.split(): - if len(word) >= 4 and word not in words: - words.append(word) - self.input.auto_completion(words, ' ') - - def on_enter(self): - txt = 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')) - else: - if txt.startswith('//'): - txt = txt[1:] - self.command_say(txt) - - def command_say(self, line): - raise NotImplementedError - -class MucTab(ChatTab): - """ - The tab containing a multi-user-chat room. - It contains an userlist, an input, a topic, an information and a chat zone - """ - def __init__(self, core, room): - ChatTab.__init__(self, core, room) - self.topic_win = windows.Topic() - self.text_win = windows.TextWin() - self.v_separator = windows.VerticalSeparator() - self.user_win = windows.UserList() - self.info_header = windows.MucInfoWin() - self.info_win = windows.TextWin() - self.tab_win = windows.GlobalInfoBar() - self.input = windows.MessageInput() - self.ignores = [] # set of Users - # keys - self.key_func['^I'] = self.completion - self.key_func['M-i'] = self.completion - # commands - self.commands['ignore'] = (self.command_ignore, _("Usage: /ignore <nickname> \nIgnore: Ignore a specified nickname."), None) - self.commands['unignore'] = (self.command_unignore, _("Usage: /unignore <nickname>\nUnignore: Remove the specified nickname from the ignore list."), None) - self.commands['kick'] = (self.command_kick, _("Usage: /kick <nick> [reason]\nKick: Kick the user with the specified nickname. You also can give an optional reason."), None) - self.commands['topic'] = (self.command_topic, _("Usage: /topic <subject>\nTopic: Change the subject of the room"), None) - self.commands['query'] = (self.command_query, _('Usage: /query <nick> [message]\nQuery: 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>\nNick: Change your nickname in the current room"), None) - self.commands['recolor'] = (self.command_recolor, _('Usage: /recolor\nRecolor: 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) - self.resize() - - 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] - i+= 1 - 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) - - def resize(self): - """ - Resize the whole window. i.e. all its sub-windows - """ - Tab.resize(self) - text_width = (self.width//10)*9 - 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) - 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) - 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.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, informations, _): - if not self.visible: - return - self.topic_win.refresh(self._room.topic) - self.text_win.refresh(self._room) - self.v_separator.refresh() - self.user_win.refresh(self._room.users) - self.info_header.refresh(self._room) - self.info_win.refresh(informations) - self.tab_win.refresh(tabs, tabs[0]) - self.input.refresh() - - 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 completion(self): - """ - Called when Tab is pressed, complete the nickname in the input - """ - if self.complete_commands(self.input): - return - compare_users = lambda x: x.last_talked - word_list = [user.nick for user in sorted(self._room.users, key=compare_users, reverse=True)] - 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) - - 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 - - def get_room(self): - return self._room - - def on_lose_focus(self): - self._room.set_color_state(theme.COLOR_TAB_NORMAL) - self._room.remove_line_separator() - self._room.add_line_separator() - - def on_gain_focus(self): - self._room.set_color_state(theme.COLOR_TAB_CURRENT) - curses.curs_set(1) - - def on_scroll_up(self): - self._room.scroll_up(self.text_win.height-1) - - def on_scroll_down(self): - self._room.scroll_down(self.text_win.height-1) - - def on_info_win_size_changed(self): - text_width = (self.width//10)*9 - 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) - - def just_before_refresh(self): - return - - def on_close(self): - return - -class PrivateTab(ChatTab): - """ - The tab containg a private conversation (someone from a MUC) - """ - def __init__(self, core, room): - ChatTab.__init__(self, core, room) - self.text_win = windows.TextWin() - self.info_header = windows.PrivateInfoWin() - self.info_win = windows.TextWin() - self.tab_win = windows.GlobalInfoBar() - self.input = windows.MessageInput() - # keys - self.key_func['^I'] = self.completion - self.key_func['M-i'] = self.completion - # commands - self.commands['unquery'] = (self.command_unquery, _("Usage: /unquery\nUnquery: close the tab"), None) - self.commands['part'] = (self.command_unquery, _("Usage: /part\Part: close the tab"), None) - self.resize() - - def completion(self): - self.complete_commands(self.input) - - 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() - - def resize(self): - Tab.resize(self) - 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) - 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, informations, _): - if not self.visible: - return - self.text_win.refresh(self._room) - self.info_header.refresh(self._room) - 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): - 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._room.set_color_state(theme.COLOR_TAB_NORMAL) - self._room.remove_line_separator() - self._room.add_line_separator() - - def on_gain_focus(self): - self._room.set_color_state(theme.COLOR_TAB_CURRENT) - curses.curs_set(1) - - def on_scroll_up(self): - self._room.scroll_up(self.text_win.height-1) - - def on_scroll_down(self): - self._room.scroll_down(self.text_win.height-1) - - def on_info_win_size_changed(self): - 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) - - def get_room(self): - return self._room - - def just_before_refresh(self): - return - - def on_close(self): - return - -class RosterInfoTab(Tab): - """ - A tab, splitted in two, containing the roster and infos - """ - def __init__(self, core): - Tab.__init__(self, core) - self.name = "Roster" - self.v_separator = windows.VerticalSeparator() - self.tab_win = windows.GlobalInfoBar() - self.info_win = windows.TextWin() - self.roster_win = windows.RosterWin() - self.contact_info_win = windows.ContactInfoWin() - self.default_help_message = windows.HelpText("Enter commands with “/”. “o”: toggle offline show") - self.input = self.default_help_message - self.set_color_state(theme.COLOR_TAB_NORMAL) - 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 - self.key_func["^F"] = self.start_search - self.resize() - - def resize(self): - Tab.resize(self) - roster_width = self.width//2 - info_width = self.width-roster_width-1 - 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) - self.info_win.resize(self.height-2, info_width, 0, roster_width+1, self.core.stdscr) - self.roster_win.resize(self.height-2-3, roster_width, 0, 0, self.core.stdscr) - self.contact_info_win.resize(3, roster_width, self.height-2-3, 0, self.core.stdscr) - self.input.resize(1, self.width, self.height-1, 0, self.core.stdscr) - - 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) - - def refresh(self, tabs, informations, roster): - if not self.visible: - return - self.v_separator.refresh() - self.roster_win.refresh(roster) - self.contact_info_win.refresh(self.roster_win.get_selected_row()) - 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): - res = self.input.do_command(key) - if res: - return True - if key in self.key_func: - return self.key_func[key]() - - 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 - - def on_slash(self): - """ - '/' is pressed, we enter "input mode" - """ - 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 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() - - 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 add_message(self): - return False - - def move_cursor_down(self): - self.roster_win.move_cursor_down() - return True - - def move_cursor_up(self): - self.roster_win.move_cursor_up() - return True - - def on_scroll_down(self): - # Scroll info win - pass - - def on_scroll_up(self): - # Scroll info down - pass - - def on_info_win_size_changed(self): - pass - - 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 - - def on_enter(self): - selected_row = self.roster_win.get_selected_row() - self.core.on_roster_enter_key(selected_row) - return selected_row - - def start_search(self): - """ - Start the search. The input should appear with a short instruction - in it. - """ - curses.curs_set(1) - 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) - return True - - def set_roster_filter(self, txt): - roster._contact_filter = (jid_and_name_match, txt) - self.roster_win.refresh(roster) - return False - - def on_search_terminate(self, txt): - curses.curs_set(0) - roster._contact_filter = None - self.reset_help_message() - return True - - def just_before_refresh(self): - return - - def on_close(self): - return - -class ConversationTab(ChatTab): - """ - The tab containg a normal conversation (someone from our roster) - """ - def __init__(self, core, text_buffer, jid): - ChatTab.__init__(self, core, text_buffer) - self.color_state = theme.COLOR_TAB_NORMAL - self._name = jid # a conversation tab is linked to one specific full jid OR bare jid - self.text_win = windows.TextWin() - self.upper_bar = windows.ConversationStatusMessageWin() - self.info_header = windows.ConversationInfoWin() - self.info_win = windows.TextWin() - self.tab_win = windows.GlobalInfoBar() - self.input = windows.MessageInput() - # keys - self.key_func['^I'] = self.completion - self.key_func['M-i'] = self.completion - # commands - self.commands['unquery'] = (self.command_unquery, _("Usage: /unquery\nUnquery: close the tab"), None) - self.commands['part'] = (self.command_unquery, _("Usage: /part\Part: close the tab"), None) - self.resize() - - def completion(self): - self.complete_commands(self.input) - - 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): - """ - /unquery - """ - self.core.close_tab() - - def resize(self): - Tab.resize(self) - self.text_win.resize(self.height-3-self.core.information_win_size, self.width, 1, 0, self.core.stdscr) - 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) - self.info_win.resize(self.core.information_win_size, self.width, self.height-2-self.core.information_win_size, 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, informations, roster): - if not self.visible: - return - self.text_win.refresh(self._room) - self.upper_bar.refresh(self.get_name(), roster.get_contact_by_jid(self.get_name())) - self.info_header.refresh(self.get_name(), roster.get_contact_by_jid(self.get_name()), self._room) - self.info_win.refresh(informations) - self.tab_win.refresh(tabs, tabs[0]) - self.input.refresh() - - def get_color_state(self): - if self.color_state == theme.COLOR_TAB_NORMAL or\ - self.color_state == theme.COLOR_TAB_CURRENT: - return self.color_state - return theme.COLOR_TAB_PRIVATE - - def set_color_state(self, color): - self.color_state = color - - def get_name(self): - return self._name - - 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.set_color_state(theme.COLOR_TAB_NORMAL) - self._room.remove_line_separator() - self._room.add_line_separator() - - def on_gain_focus(self): - self.set_color_state(theme.COLOR_TAB_CURRENT) - curses.curs_set(1) - - def on_scroll_up(self): - self._room.scroll_up(self.text_win.height-1) - - def on_scroll_down(self): - self._room.scroll_down(self.text_win.height-1) - - def on_info_win_size_changed(self): - 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) - - def get_room(self): - return self._room - - def just_before_refresh(self): - return - - def on_close(self): - return - -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 - -def jid_and_name_match(contact, txt): - """ - A function used to know if a contact in the roster should - be shown in the roster - """ - 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()): - return True - return False |