#!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = "duc_tin" __copyright__ = "Copyright 2015+, duc_tin" __license__ = "GPLv2" __version__ = "1.25" __maintainer__ = "duc_tin" __email__ = "nguyenbaduc.tin@gmail.com" import urwid import re class MyText(urwid.Text): signals = ['click'] def __init__(self, markup, wrap='clip'): super(MyText, self).__init__(markup, wrap=wrap) self._selectable = True def keypress(self, size, key): if key == 'f10': self._emit('click') else: return key class MyButton(urwid.Button): def __init__(self, caption, callback): super(MyButton, self).__init__(caption) urwid.connect_signal(self, 'click', callback) self._w = urwid.AttrMap(urwid.SelectableIcon([u' \N{BULLET} ', caption], 1), None, 'popbgs') def update_label(self, newcap): caption = newcap self._w = urwid.AttrMap(urwid.SelectableIcon([u' \N{BULLET} ', caption], 1), None, 'popbgs') class MyColumn(urwid.Columns): def __init__(self, widget_list, dividechars=1, focus_column=None, min_width=1, box_columns=None): super(MyColumn, self).__init__(widget_list, dividechars, focus_column, min_width, box_columns) self.receiver = {} for col, widget in enumerate(widget_list): if hasattr(widget, 'trigger') and widget.trigger: self.receiver[widget.trigger] = col def keypress(self, size, key): if key == 'up': return key if key in self.receiver: receiver = self.receiver[key] self.set_focus_column(receiver) return super(MyColumn, self).keypress(size, key) class MyPile(urwid.Pile): def __init__(self, widget_list, focus_item=None): super(MyPile, self).__init__(widget_list, focus_item) def keypress(self, size, key): if key == 'up': return key if len(key) == 2 and 'f' in key: self.focus_position = 0 else: self.focus_position = 1 return super(MyPile, self).keypress(size, key) class PopUpSortBy(urwid.WidgetWrap): """A dialog that appears with nothing but a close button """ signals = ['close'] def __init__(self, key=None, value=''): self.chosen = 'ping' if value == '' else value self.trigger = key ping = MyButton("ping", self.item_callback) speed = MyButton("speed", self.item_callback) uptime = MyButton("up time", self.item_callback) score = MyButton("score", self.item_callback) default = {'ping': 0, 'speed': 1, 'up time': 2, 'score': 3} self.pile = urwid.Pile([ping, speed, uptime, score], focus_item=default[self.chosen]) fill = urwid.LineBox(urwid.Filler(self.pile)) self.__super.__init__(urwid.AttrWrap(fill, 'popbg')) def item_callback(self, Button, data=None): self.chosen = self.pile.focus.label self._emit("close") def keypress(self, size, key): if key in [self.trigger, 'esc']: self._emit("close") return self.trigger else: self.pile.keypress(size, key) class PopUpCountry(urwid.WidgetWrap): """A dialog that appears with nothing but a close button """ signals = ['close'] def __init__(self, key=None, value=''): self.trigger = key info = urwid.Text("'ESC' to clear, leave blank or 'all' for all country and port", 'center') self.country = urwid.Edit(('attention', u' \N{BULLET} Country: '), edit_text=value[0], wrap='clip') self.port = urwid.Edit(('attention', u' \N{BULLET} Port : '), edit_text=value[1], wrap='clip') self.score = urwid.Edit(('attention', u' \N{BULLET} Score >: '), edit_text=value[2], wrap='clip') exit_but = urwid.Padding(urwid.Button('OKay'.center(8), self.item_callback), 'center', 12) filter_ = [urwid.AttrMap(wid, None, 'popbgs') for wid in (self.country, self.port, self.score, exit_but)] self.pile = urwid.Pile([info]+filter_) fill = urwid.LineBox(urwid.Filler(self.pile)) self.__super.__init__(urwid.AttrWrap(fill, 'popbg')) self.chosen = value def item_callback(self, Button, data=None): country = self.country.edit_text port = self.port.edit_text score = self.score.edit_text if not country: self.country.set_edit_text('all') country = 'all' if not port: self.port.set_edit_text('all') port = 'all' elif port != 'all' and not set(port) <= set(' <>0123456789'): self.port.set_edit_text('Invalid number!') return elif port[0] == ' ': self.port.set_edit_text('Invalid number!') return elif ('<' in port or '>' in port) and port[0].isdigit(): self.port.set_edit_text('Invalid number!') return else: for p in re.findall(r'\d+', port): if p == 'Invalid number!': return if p != 'all' and not 0 <= int(p) <= 65535: self.port.set_edit_text('Invalid number!') return if not score: self.score.set_edit_text('all') score = 'all' elif score != 'all' and not set(score) <= set('0123456789'): self.score.set_edit_text('Invalid number!') return self.chosen = country, port, score self._emit("close") def keypress(self, size, key): position = self.pile.focus_position if key == self.trigger: self.country.set_edit_text(self.chosen[0]) self.port.set_edit_text(self.chosen[1]) self._emit("close") elif key == 'esc': if position == 1 and self.country.edit_text: self.country.set_edit_text('') elif position == 2 and self.port.edit_text: self.port.set_edit_text('') else: self.country.set_edit_text(self.chosen[0]) self.port.set_edit_text(self.chosen[1]) self._emit("close") elif key == 'enter' and 0 < position < len(self.pile.widget_list)-1: self.pile.focus_position += 1 else: self.pile.keypress((size[0],), key) class PopUpProxy(urwid.WidgetWrap): """A dialog that appears with nothing but a close button """ signals = ['close'] def __init__(self, key=None, value=('', '')): self.trigger = key self.yn = value[0] self.yn_but = MyButton([('attention', 'Use proxy: '), self.yn], self.on_change) self.input_addr = urwid.Edit(('attention', u' \N{BULLET} Address : '), edit_text=value[1], wrap='clip') self.input_port = urwid.IntEdit(('attention', u' \N{BULLET} Port : '), default=value[2]) self.input_port.set_wrap_mode('clip') exit_but = urwid.Padding(urwid.Button('OKay'.center(8), self.item_callback), 'center', 12) widgets = [self.yn_but] \ + [urwid.AttrMap(wid, None, 'popbgs') for wid in (self.input_addr, self.input_port, exit_but)] self.pile = urwid.Pile(widgets) fill = urwid.LineBox(urwid.Filler(self.pile)) self.__super.__init__(urwid.AttrWrap(fill, 'popbg')) self.chosen = value def on_change(self, Button, data=None): self.yn = 'no' if 'y' in self.yn else 'yes' self.yn_but.update_label([('attention', 'Use proxy: '), self.yn]) def item_callback(self, Button, data=None): port = self.input_port.edit_text addr = self.input_addr.edit_text.replace('http://', '') if self.yn == 'yes': if not addr: addr = 'Invalid Address!' self.input_addr.set_edit_text('Invalid Address!') if not port: port = 'Invalid number!' self.input_port.set_edit_text('Invalid number!') if 'Invalid' in addr + port: return if not 0 <= int(port) <= 65535: self.input_port.set_edit_text('Invalid number!') else: self.chosen = self.yn, addr, port self._emit("close") else: self.chosen = self.yn, addr, port self._emit("close") def keypress(self, size, key): position = self.pile.focus_position if key == self.trigger: self.input_addr.set_edit_text(self.chosen[1]) self.input_port.set_edit_text(self.chosen[2]) self._emit("close") elif key == 'esc': if position == 1 and self.input_addr.edit_text: self.input_addr.set_edit_text('') elif position == 2 and self.input_port.edit_text: self.input_port.set_edit_text('') else: self.input_addr.set_edit_text(self.chosen[1]) self.input_port.set_edit_text(self.chosen[2]) self._emit("close") elif key == 'enter' and 0 < position < len(self.pile.widget_list)-1: self.pile.focus_position += 1 else: self.pile.keypress((size[0],), key) class PopUpDNS(urwid.WidgetWrap): """A dialog that appears with nothing but a close button """ signals = ['close'] def __init__(self, key=None, value=('', '')): self.trigger = key self.yn = value[0] self.yn_but = MyButton([('attention', 'Fix it: '), self.yn], self.on_change) self.input_dns = urwid.Edit(('attention', u' \N{BULLET} DNS : '), edit_text=value[1], wrap='clip') exit_but = urwid.Padding(urwid.Button('OKay'.center(8), self.item_callback), 'center', 12) widgets = [self.yn_but] + [urwid.AttrMap(wid, None, 'popbgs') for wid in (self.input_dns, exit_but)] self.pile = urwid.Pile(widgets) fill = urwid.LineBox(urwid.Filler(self.pile)) self.__super.__init__(urwid.AttrWrap(fill, 'popbg')) self.chosen = value def on_change(self, Button, data=None): self.yn = 'no' if 'y' in self.yn else 'yes' self.yn_but.update_label([('attention', 'Fix it: '), self.yn]) def item_callback(self, Button, data=None): self.chosen = self.yn, self.input_dns.edit_text self._emit("close") def keypress(self, size, key): position = self.pile.focus_position if key in [self.trigger, 'esc']: self.input_dns.set_edit_text(self.chosen[1]) self._emit("close") elif key == 'enter' and 0 < position < len(self.pile.widget_list)-1: self.pile.focus_position += 1 else: self.pile.keypress((size[0],), key) class AddPopUp(urwid.PopUpLauncher): signals = ['done'] def __init__(self, target_widget, popup, value, trigger, size): self.__super.__init__(target_widget) self.popup = popup(key=trigger, value=value) self.trigger = trigger self.size = size self.result = value def create_pop_up(self): # this method must be exist due to its blank content in original class urwid.connect_signal(self.popup, 'close', self.close_pop) return self.popup def get_pop_up_parameters(self): l, t, w, h = self.size # 3, 1, 12, 6 return {'left': l, 'top': t, 'overlay_width': w, 'overlay_height': h} def keypress(self, size, key): if key == self.trigger: self.open_pop_up() else: return key def close_pop(self, button): self.result = button.chosen self.close_pop_up() self._emit('done', self.trigger)