From 2e2851dc13d73352530dd4495c7e05603b2e520d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 23:38:38 +0200 Subject: Adding upstream version 2.1.2~dev0+20240219. Signed-off-by: Daniel Baumann --- deluge/ui/console/modes/torrentlist/search_mode.py | 206 +++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 deluge/ui/console/modes/torrentlist/search_mode.py (limited to 'deluge/ui/console/modes/torrentlist/search_mode.py') diff --git a/deluge/ui/console/modes/torrentlist/search_mode.py b/deluge/ui/console/modes/torrentlist/search_mode.py new file mode 100644 index 0000000..6f79628 --- /dev/null +++ b/deluge/ui/console/modes/torrentlist/search_mode.py @@ -0,0 +1,206 @@ +# +# Copyright (C) 2011 Nick Lanham +# +# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with +# the additional special exception to link portions of this program with the OpenSSL library. +# See LICENSE for more details. +# + +import logging + +from deluge.decorators import overrides +from deluge.ui.console.modes.basemode import InputKeyHandler, move_cursor +from deluge.ui.console.modes.torrentlist.torrentactions import torrent_actions_popup +from deluge.ui.console.utils import curses_util as util + +try: + import curses +except ImportError: + pass + +log = logging.getLogger(__name__) +QUEUE_MODE_HELP_STR = """ +Change queue position of selected torrents + +{!info!}'+'{!normal!} - {|indent_pos:|}Move up +{!info!}'-'{!normal!} - {|indent_pos:|}Move down + +{!info!}'Home'{!normal!} - {|indent_pos:|}Move to top +{!info!}'End'{!normal!} - {|indent_pos:|}Move to bottom + +""" +SEARCH_EMPTY = 0 +SEARCH_FAILING = 1 +SEARCH_SUCCESS = 2 +SEARCH_START_REACHED = 3 +SEARCH_END_REACHED = 4 +SEARCH_FORMAT = { + SEARCH_EMPTY: '{!black,white!}Search torrents: %s{!black,white!}', + SEARCH_SUCCESS: '{!black,white!}Search torrents: {!black,green!}%s{!black,white!}', + SEARCH_FAILING: '{!black,white!}Search torrents: {!black,red!}%s{!black,white!}', + SEARCH_START_REACHED: '{!black,white!}Search torrents: {!black,yellow!}%s{!black,white!} (start reached)', + SEARCH_END_REACHED: '{!black,white!}Search torrents: {!black,yellow!}%s{!black,white!} (end reached)', +} + + +class SearchMode(InputKeyHandler): + def __init__(self, torrentlist): + super().__init__() + self.torrentlist = torrentlist + self.torrentview = torrentlist.torrentview + self.search_state = SEARCH_EMPTY + self.search_string = '' + + def update_cursor(self): + util.safe_curs_set(util.Curser.VERY_VISIBLE) + move_cursor( + self.torrentlist.stdscr, + self.torrentlist.rows - 1, + len(self.search_string) + 17, + ) + + def set_statusbar_args(self, statusbar_args): + statusbar_args['bottombar'] = ( + SEARCH_FORMAT[self.search_state] % self.search_string + ) + statusbar_args['bottombar_help'] = False + + def update_colors(self, tidx, colors): + if len(self.search_string) > 1: + lcase_name = self.torrentview.torrent_names[tidx].lower() + sstring_lower = self.search_string.lower() + if lcase_name.find(sstring_lower) != -1: + if tidx == self.torrentview.cursel: + pass + elif tidx in self.torrentview.marked: + colors['bg'] = 'magenta' + else: + colors['bg'] = 'green' + if colors['fg'] == 'green': + colors['fg'] = 'black' + colors['attr'] = 'bold' + + def do_search(self, direction='first'): + """ + Performs a search on visible torrent and sets cursor to the match + + Args: + direction (str): The direction to search. Must be one of 'first', 'last', 'next' or 'previous' + + """ + search_space = list(enumerate(self.torrentview.torrent_names)) + + if direction == 'last': + search_space = reversed(search_space) + elif direction == 'next': + search_space = search_space[self.torrentview.cursel + 1 :] + elif direction == 'previous': + search_space = reversed(search_space[: self.torrentview.cursel]) + + search_string = self.search_string.lower() + for i, n in search_space: + n = n.lower() + if n.find(search_string) != -1: + self.torrentview.cursel = i + if ( + self.torrentview.curoff + + self.torrentview.torrent_rows + - self.torrentview.torrentlist_offset + ) < self.torrentview.cursel: + self.torrentview.curoff = ( + self.torrentview.cursel - self.torrentview.torrent_rows + 1 + ) + elif (self.torrentview.curoff + 1) > self.torrentview.cursel: + self.torrentview.curoff = max(0, self.torrentview.cursel) + self.search_state = SEARCH_SUCCESS + return + if direction in ['first', 'last']: + self.search_state = SEARCH_FAILING + elif direction == 'next': + self.search_state = SEARCH_END_REACHED + elif direction == 'previous': + self.search_state = SEARCH_START_REACHED + + @overrides(InputKeyHandler) + def handle_read(self, c): + cname = self.torrentview.torrent_names[self.torrentview.cursel] + refresh = True + + if c in [ + util.KEY_ESC, + util.KEY_BELL, + ]: # If Escape key or CTRL-g, we abort search + self.torrentlist.set_minor_mode(None) + self.search_state = SEARCH_EMPTY + elif c in [curses.KEY_BACKSPACE, util.KEY_BACKSPACE2]: + if self.search_string: + self.search_string = self.search_string[:-1] + if cname.lower().find(self.search_string.lower()) != -1: + self.search_state = SEARCH_SUCCESS + else: + self.torrentlist.set_minor_mode(None) + self.search_state = SEARCH_EMPTY + elif c == curses.KEY_DC: + self.search_string = '' + self.search_state = SEARCH_SUCCESS + elif c == curses.KEY_UP: + self.do_search('previous') + elif c == curses.KEY_DOWN: + self.do_search('next') + elif c == curses.KEY_LEFT: + self.torrentlist.set_minor_mode(None) + self.search_state = SEARCH_EMPTY + elif c == ord('/'): + self.torrentlist.set_minor_mode(None) + self.search_state = SEARCH_EMPTY + elif c == curses.KEY_RIGHT: + tid = self.torrentview.current_torrent_id() + self.torrentlist.show_torrent_details(tid) + refresh = False + elif c == curses.KEY_HOME: + self.do_search('first') + elif c == curses.KEY_END: + self.do_search('last') + elif c in [10, curses.KEY_ENTER]: + self.last_mark = -1 + tid = self.torrentview.current_torrent_id() + torrent_actions_popup(self.torrentlist, [tid], details=True) + refresh = False + elif c == util.KEY_ESC: + self.search_string = '' + self.search_state = SEARCH_EMPTY + elif c > 31 and c < 256: + old_search_string = self.search_string + stroke = chr(c) + uchar = stroke + while not uchar: + try: + uchar = stroke.decode(self.torrentlist.encoding) + except UnicodeDecodeError: + c = self.torrentlist.stdscr.getch() + stroke += chr(c) + + if uchar: + self.search_string += uchar + + still_matching = ( + cname.lower().find(self.search_string.lower()) + == cname.lower().find(old_search_string.lower()) + and cname.lower().find(self.search_string.lower()) != -1 + ) + + if self.search_string and not still_matching: + self.do_search() + elif self.search_string: + self.search_state = SEARCH_SUCCESS + else: + refresh = False + + if not self.search_string: + self.search_state = SEARCH_EMPTY + refresh = True + + if refresh: + self.torrentlist.refresh([]) + + return util.ReadState.READ -- cgit v1.2.3