Esempio n. 1
0
class Menu(Dialog):#{{{

    def __init__(self, menu_items, focus_item=0, **kwargs):#{{{
        # menu items: ( (text, attr), (callback, args), shortcut )
        self.item_list = SimpleListWalker([])
        listbox = ListBox(self.item_list)
        self.__super.__init__(listbox, keypress=self.on_keypress, **kwargs)

        self.attr_style = 'dialog.menu'
        self.title_attr_style = 'dialog.menu.title'
        self.shortcuts = {}

        def wrap(callback):
            if callback:
                def w(*args):
                    self.install_callback(callback, args)
                    self.quit()
                w.__name__ = callback.__name__
                w.__doc__ = callback.__doc__
                return w
            return None


        for item in menu_items:
            tag_attr = item[0]
            if len(item) > 1:
                ca = item[1]
                if isinstance(ca, tuple):
                    if len(ca) == 2:
                        cb, args = ca
                    else:
                        cb, args = ca, ()
                else:
                    cb = ca
                    args = ()
                if not callable(cb):
                    raise ValueError("You must pass a callable callback")
            else:
                cb, args = None, ()
            self.item_list.append(AttrMap(MenuItem(tag_attr, wrap(cb), args),
                                  'dialog.menu.item', 'dialog.menu.item.focus'))
            if len(item) > 2:
                self.shortcuts[item[2]] = len(self.item_list) - 1

        self.item_list.set_focus(focus_item)
#}}}
    def on_keypress(self, key):#{{{
        if key == "esc":
            self.quit()
        elif key in self.shortcuts:
            self.item_list[self.shortcuts[key]].original_widget.activate()
        return key
Esempio n. 2
0
class Sidebar(BoxWidget):
    signals = ['select', 'search']

    def __init__(self, phones):
        self.phone_edit = EnterEdit('Phone:', '')
        self.chan_edit = EnterEdit('Chanl:', '')
        self.call_id_edit = EnterEdit('SipID:', '')
        self.text_edit = EnterEdit('Find:', '')
        connect_signal(self.phone_edit, 'enter', self.on_change, 'phone')
        connect_signal(self.chan_edit, 'enter', self.on_change, 'chan')
        connect_signal(self.call_id_edit, 'enter', self.on_change, 'call_id')
        connect_signal(self.text_edit, 'enter', self.on_change, 'text')
        self.phones_text = Text([('key', 'F4'), ' Phones'])
        self.head = Pile([
            AttrWrap(Text([('key', 'F3'), ' Search']), 'bar'),
            AttrWrap(self.phone_edit, 'no', 'selection'),
            AttrWrap(self.chan_edit, 'no', 'selection'),
            AttrWrap(self.call_id_edit, 'no', 'selection'),
            Divider('-'),
            AttrWrap(self.text_edit, 'no', 'selection'),
            AttrWrap(self.phones_text, 'bar'),
        ])
        self.items = SimpleListWalker([])
        self.set_results(phones)
        self.listbox = ListBox(self.items)
        self.frame = Frame(self.listbox, header=self.head)

    def set_results(self, results):
        self.phones_text.set_text([('key', 'F4'),
                                   ' Results (%s)' % len(results)])
        self.items[:] = []
        group = []
        for ref in results:
            item = RadioButton(group, ref, state=False)
            connect_signal(item, 'change', self.on_select_phone, ref)
            item = AttrWrap(item, 'no', 'selection')
            self.items.append(item)

    def render(self, size, focus=False):
        return self.frame.render(size, focus)

    def keypress(self, size, key):
        return self.frame.keypress(size, key)

    # noinspection PyUnusedLocal
    def on_select_phone(self, button, new_state, call_id):
        if new_state:
            self._emit('select', call_id)

    # noinspection PyUnusedLocal
    def on_change(self, widget, value, field_name):
        self._emit('search', field_name, value)
Esempio n. 3
0
class Tab(object):

    __metaclass__ = MetaSignals
    signals = ["child_added", "child_removed", "remove", "connected"]

    _valid_stati = [
        "informative", "actions", "actions_highlight", "actions_own",
        "messages", "messages_highlight", "messages_own"
    ]

    def __repr__(self):
        return "<tab: %s:%s:%s>" % (type(self).__name__, self._parent,
                                    self.name)

    def __str__(self):
        return self.name

    # Properties

    @types(switch=bool)
    def set_connected(self, switch):
        self._connected = switch

        for child in self.children:
            child.set_connected(switch)

        urwid.emit_signal(self, "connected", switch)

    connected = property(lambda x: x._connected, set_connected)

    def set_input_text(self, text):
        self._input_text = text

    input_text = property(lambda x: x._input_text, set_input_text)

    # Methods

    @types(name=(String, str, unicode))
    def __init__(self, name):
        self.name = name

        self._connected = False
        self._parent = None

        self.status = {}
        self.children = []
        self.input_history = None
        self.output_walker = SimpleListWalker([])
        self.input_text = ""
        self.auto_scroll = True

        self.read_line_index = -1

    def set_readline(self):
        if self.read_line_index != -1:
            try:
                del self.output_walker[self.read_line_index]
            except IndexError:
                pass

        line = Text("-" * 30)
        line.set_align_mode("center")
        self.output_walker.append(line)
        self.read_line_index = len(self.output_walker) - 1

    def child_added(self, child):
        urwid.emit_signal(self, "child_added", self, child)
        child.set_connected(self.connected)
        self.children.append(child)

    def child_removed(self, child):
        urwid.emit_signal(self, "child_removed", self, child)
        try:
            i = self.children.index(child)
        except ValueError:
            pass
        else:
            del self.children[i]

    def set_parent(self, parent):
        if parent in self.children:
            print "Loop detected in '%s'.set_parent(%s)" % (self, parent)
            return

        try:
            self._parent.child_removed(self)
        except AttributeError:
            pass

        self._parent = parent

        try:
            self._parent.child_added(self)
        except AttributeError:
            pass

    parent = property(lambda x: x._parent, set_parent)

    def remove(self):
        """ emit remove signals """
        for child in self.children:
            child.remove()
            self.child_removed(child)
        urwid.emit_signal(self, "remove")
        self.set_parent(None)

    @types(name=str)
    def add_status(self, name):
        if name in self._valid_stati:
            self.status[name] = True

    @types(status=str)
    def has_status(self, status):
        return self.status.has_key(status)

    @types(name=str)
    def remove_status(self, name):
        try:
            del self.status[name]
        except KeyError:
            pass

    def reset_status(self):
        self.status = {}

    def print_last_log(self, lines=0):
        """	Fetch the given amount of lines of history for
			the channel on the given server and print it to the
			channel's textview.
		"""
        lines = UInt64(lines or config.get("chatting", "last_log_lines", "0"))

        if type(self) == Server:
            server = self.name
            channel = ""
        else:
            server = self.parent.name
            channel = self.name

        for line in connection.sushi.log(server, channel, lines):
            self.output_walker.append(Text(unicode(line)))
Esempio n. 4
0
class CursesGUI(object):
    def __init__(self,
                 choice_callback=None,
                 command_callback=None,
                 help_callback=None):

        self.palette = [
            ('brick', 'light red', 'black'),
            ('rubble', 'yellow', 'black'),
            ('wood', 'light green', 'black'),
            ('concrete', 'white', 'black'),
            ('stone', 'light cyan', 'black'),
            ('marble', 'light magenta', 'black'),
            ('jack', 'dark gray', 'white'),
            ('msg_info', 'white', 'black'),
            ('msg_err', 'light red', 'black'),
            ('msg_debug', 'light green', 'black'),
        ]

        self.choice_callback = choice_callback
        self.command_callback = command_callback
        self.help_callback = help_callback

        self.screen = None
        self.loop = None
        self.called_loop_stop = False
        self.reactor_stop_fired = False

        self.quit_flag = False
        self.edit_msg = "Make selection ('q' to quit): "
        self.roll_list = SimpleListWalker([])
        self.game_log_list = SimpleListWalker([])
        self.choices_list = SimpleListWalker([])

        self.state_text = SimpleListWalker([Text('Connecting...')])

        self.edit_widget = Edit(self.edit_msg)
        self.roll = ListBox(self.roll_list)
        self.game_log = ListBox(self.game_log_list)
        self.choices = ListBox(self.choices_list)
        self.state = ListBox(self.state_text)

        self.left_frame = Pile([
            LineBox(self.state),
            (13, LineBox(self.choices)),
        ])

        self.right_frame = Pile([LineBox(self.game_log), LineBox(self.roll)])

        self.state.set_focus(len(self.state_text) - 1)

        self.columns = Columns([('weight', 0.75, self.left_frame),
                                ('weight', 0.25, self.right_frame)])
        self.frame_widget = Frame(footer=self.edit_widget,
                                  body=self.columns,
                                  focus_part='footer')

        self.exc_info = None

    def register_loggers(self):
        """Gets the global loggers and sets up log handlers.
        """
        self.game_logger_handler = RollLogHandler(self._roll_write)
        self.logger_handler = RollLogHandler(self._roll_write)

        self.game_logger = logging.getLogger('gtr.game')
        self.logger = logging.getLogger('gtr')

        self.logger.addHandler(self.logger_handler)
        self.game_logger.addHandler(self.game_logger_handler)

        #self.set_log_level(logging.INFO)

    def unregister_loggers(self):
        self.game_logger.removeHandler(self.game_logger_handler)
        self.logger.removeHandler(self.logger_handler)

    def fail_safely(f):
        """Wraps functions in this class to catch arbitrary exceptions,
        shut down the event loop and reset the terminal to a normal state.

        It then re-raises the exception.
        """
        @wraps(f)
        def wrapper(self, *args, **kwargs):
            retval = None
            try:
                retval = f(self, *args, **kwargs)
            except urwid.ExitMainLoop:
                from twisted.internet import reactor
                if not self.reactor_stop_fired and reactor.running:
                    # Make sure to call reactor.stop once
                    reactor.stop()
                    self.reactor_stop_fired = True

            except:
                #pdb.set_trace()
                from twisted.internet import reactor
                if not self.reactor_stop_fired and reactor.running:
                    # Make sure to call reactor.stop once
                    reactor.stop()
                    self.reactor_stop_fired = True

                if not self.called_loop_stop:
                    self.called_loop_stop = True
                    self.loop.stop()

                # Save exception info for printing later outside the GUI.
                self.exc_info = sys.exc_info()

                raise

            return retval

        return wrapper

    def set_log_level(self, level):
        """Set the log level as per the standard library logging module.

        Default is logging.INFO.
        """
        logging.getLogger('gtr.game').setLevel(level)
        logging.getLogger('gtr').setLevel(level)

    def run(self):
        loop = MainLoop(self.frame_widget, unhandled_input=self.handle_input)
        loop.run()

    def run_twisted(self):
        from twisted.internet import reactor
        evloop = urwid.TwistedEventLoop(reactor, manage_reactor=False)
        self.screen = urwid.raw_display.Screen()
        self.screen.register_palette(self.palette)
        self.loop = MainLoop(self.frame_widget,
                             unhandled_input=self.handle_input,
                             screen=self.screen,
                             event_loop=evloop)
        self.loop.set_alarm_in(0.1, lambda loop, _: loop.draw_screen())

        self.loop.start()

        # The loggers get a Handler that writes to the screen. We want this to only
        # happen if the screen exists, so de-register them after the reactor stops.
        reactor.addSystemEventTrigger('after', 'startup',
                                      self.register_loggers)
        reactor.addSystemEventTrigger('before', 'shutdown',
                                      self.unregister_loggers)
        reactor.run()

        # We might have stopped the screen already, and the stop() method
        # doesn't check for stopping twice.
        if self.called_loop_stop:
            self.logger.warn('Internal error!')
        else:
            self.loop.stop()
            self.called_loop_stop = True

    @fail_safely
    def handle_input(self, key):
        if key == 'enter':
            text = self.edit_widget.edit_text
            if text in ['q', 'Q']:
                self.handle_quit_request()
            else:
                self.quit_flag = False

                try:
                    i = int(text)
                except ValueError:
                    i = None
                    self.handle_invalid_choice(text)

                if i is not None:
                    self.handle_choice(i)

            self.edit_widget.set_edit_text('')

    def _roll_write(self, line, attr=None):
        """Add a line to the roll with palette attributes 'attr'.

        If no attr is specified, None is used.

        Default attr is plain text
        """
        text = Text((attr, '* ' + line))

        self.roll_list.append(text)
        self.roll_list.set_focus(len(self.roll_list) - 1)
        self._modified()

    @fail_safely
    def update_state(self, state):
        """Sets the game state window via one large string.
        """
        self.logger.debug('Drawing game state.')
        self.state_text[:] = [self.colorize(s) for s in state.split('\n')]
        self._modified()

    @fail_safely
    def update_game_log(self, log):
        """Sets the game log window via one large string.
        """
        self.logger.debug('Drawing game log.')
        self.game_log_list[:] = [self.colorize(s) for s in log.split('\n')]
        self.game_log_list.set_focus(len(self.game_log_list) - 1)
        self._modified()

    @fail_safely
    def update_choices(self, choices):
        """Update choices list.
        """
        self.choices_list[:] = [self.colorize(str(c)) for c in choices]
        self._modified()

        length = len([c for c in choices if c[2] == '['])
        i = randint(1, length) if length else 0
        self.choices_list.append(
            self.colorize('\nPicking random choice: {0} in 1s'.format(i)))
        self._modified()
        #from twisted.internet import reactor
        #reactor.callLater(1, self.handle_choice, i)

    @fail_safely
    def update_prompt(self, prompt):
        """Set the prompt for the input field.
        """
        self.edit_widget.set_caption(prompt)
        self._modified()

    def _modified(self):
        if self.loop:
            self.loop.draw_screen()

    @fail_safely
    def quit(self):
        """Quit the program.
        """
        #import pdb; pdb.set_trace()
        #raise TypeError('Artificial TypeError')
        raise urwid.ExitMainLoop()

    def handle_invalid_choice(self, s):
        if len(s):
            text = 'Invalid choice: "' + s + '". Please enter an integer.'
            self.logger.warn(text)

    def handle_quit_request(self):
        if True or self.quit_flag:
            self.quit()
        else:
            self.quit_flag = True
            text = 'Are you sure you want to quit? Press Q again to confirm.'
            self.logger.warn(text)

    def handle_choice(self, i):
        if self.choice_callback:
            self.choice_callback(i)

    def colorize(self, s):
        """Applies color to roles found in a string.

        A string with attributes applied looks like

        Text([('attr1', 'some text'), 'some more text'])

        so we need to split into a list of tuples of text.
        """
        regex_color_dict = {
            r'\b([Ll]egionaries|[Ll]egionary|[Ll]eg|LEGIONARIES|LEGIONARY|LEG)\b':
            'brick',
            r'\b([Ll]aborers?|[Ll]ab|LABORERS?|LAB)\b': 'rubble',
            r'\b([Cc]raftsmen|[Cc]raftsman|[Cc]ra|CRAFTSMEN|CRAFTSMAN|CRA)\b':
            'wood',
            r'\b([Aa]rchitects?|[Aa]rc|ARCHITECTS?|ARC)\b': 'concrete',
            r'\b([Mm]erchants?|[Mm]er|MERCHANTS?|MER)\b': 'stone',
            r'\b([Pp]atrons?|[Pp]at|PATRONS?|PAT)\b': 'marble',
            r'\b([Jj]acks?|JACKS?)\b': 'jack',
            r'\b([Bb]ricks?|[Bb]ri|BRICKS?|BRI)\b': 'brick',
            r'\b([Rr]ubble|[Rr]ub|RUBBLE|RUB)\b': 'rubble',
            r'\b([Ww]ood|[Ww]oo|WOOD|WOO)\b': 'wood',
            r'\b([Cc]oncrete|[Cc]on|CONCRETE|CON)\b': 'concrete',
            r'\b([Ss]tone|[Ss]to|STONE|STO)\b': 'stone',
            r'\b([Mm]arble|[Mm]ar|MARBLE|MAR)\b': 'marble',
        }

        def _colorize(s, regex, attr):
            """s is a tuple of ('attr', 'text'). This splits based on the regex
            and adds attr to any matches. Returns a list of tuples

            [('attr1', 'text1'), ('attr2', 'text2'), ('attr3','text3')]

            with some attributes being None if they aren't colored.
            """
            output = []
            a, t = s
            # Make a list of all tokens, split by matches
            tokens = re.split(regex, t)
            for tok in tokens:
                m = re.match(regex, tok)
                if m:
                    # matches get the new attributes
                    output.append((attr, tok))
                else:
                    # non-matches keep the old ones
                    output.append((a, tok))

            return output

        output = [(None, s)]

        for k, v in regex_color_dict.items():
            new_output = []
            for token in output:
                new_output.extend(_colorize(token, k, v))

            output[:] = new_output

        return Text(output)
Esempio n. 5
0
class CursesGUI(object):

    def __init__(self, choice_callback=None,
                       command_callback=None,
                       help_callback=None):

        self.palette = [
                ('brick', 'light red', 'black'),
                ('rubble', 'yellow', 'black'),
                ('wood', 'light green', 'black'),
                ('concrete', 'white', 'black'),
                ('stone', 'light cyan', 'black'),
                ('marble', 'light magenta', 'black'),
                ('jack', 'dark gray', 'white'),
                ('msg_info', 'white', 'black'),
                ('msg_err', 'light red', 'black'),
                ('msg_debug', 'light green', 'black'),
                ]

        self.choice_callback = choice_callback
        self.command_callback = command_callback
        self.help_callback = help_callback

        self.screen = None
        self.loop = None
        self.called_loop_stop = False
        self.reactor_stop_fired = False

        self.quit_flag = False
        self.edit_msg = "Make selection ('q' to quit): "
        self.roll_list = SimpleListWalker([])
        self.game_log_list = SimpleListWalker([])
        self.choices_list = SimpleListWalker([])

        self.state_text = SimpleListWalker([Text('Connecting...')])

        self.edit_widget = Edit(self.edit_msg)
        self.roll = ListBox(self.roll_list)
        self.game_log = ListBox(self.game_log_list)
        self.choices = ListBox(self.choices_list)
        self.state = ListBox(self.state_text)

        self.left_frame = Pile([
                LineBox(self.state),
                (13, LineBox(self.choices)),
                ])

        self.right_frame = Pile([
                LineBox(self.game_log),
                LineBox(self.roll)
                ])

        self.state.set_focus(len(self.state_text)-1)

        self.columns = Columns([('weight', 0.75, self.left_frame),
                                ('weight', 0.25, self.right_frame)
                                ])
        self.frame_widget = Frame(footer=self.edit_widget,
                                  body=self.columns,
                                  focus_part='footer')

        self.exc_info = None


    def register_loggers(self):
        """Gets the global loggers and sets up log handlers.
        """
        self.game_logger_handler = RollLogHandler(self._roll_write)
        self.logger_handler = RollLogHandler(self._roll_write)

        self.game_logger = logging.getLogger('gtr.game')
        self.logger = logging.getLogger('gtr')

        self.logger.addHandler(self.logger_handler)
        self.game_logger.addHandler(self.game_logger_handler)

        #self.set_log_level(logging.INFO)


    def unregister_loggers(self):
        self.game_logger.removeHandler(self.game_logger_handler)
        self.logger.removeHandler(self.logger_handler)


    def fail_safely(f):
        """Wraps functions in this class to catch arbitrary exceptions,
        shut down the event loop and reset the terminal to a normal state.

        It then re-raises the exception.
        """
        @wraps(f)
        def wrapper(self, *args, **kwargs):
            retval = None
            try:
                retval = f(self, *args, **kwargs)
            except urwid.ExitMainLoop:
                from twisted.internet import reactor
                if not self.reactor_stop_fired and reactor.running:
                    # Make sure to call reactor.stop once
                    reactor.stop()
                    self.reactor_stop_fired = True

            except:
                #pdb.set_trace()
                from twisted.internet import reactor
                if not self.reactor_stop_fired and reactor.running:
                    # Make sure to call reactor.stop once
                    reactor.stop()
                    self.reactor_stop_fired = True

                if not self.called_loop_stop:
                    self.called_loop_stop = True
                    self.loop.stop()
                
                # Save exception info for printing later outside the GUI.
                self.exc_info = sys.exc_info()

                raise

            return retval

        return wrapper
                

    def set_log_level(self, level):
        """Set the log level as per the standard library logging module.

        Default is logging.INFO.
        """
        logging.getLogger('gtr.game').setLevel(level)
        logging.getLogger('gtr').setLevel(level)


    def run(self):
        loop = MainLoop(self.frame_widget, unhandled_input=self.handle_input)
        loop.run()

    def run_twisted(self):
        from twisted.internet import reactor
        evloop = urwid.TwistedEventLoop(reactor, manage_reactor=False)
        self.screen = urwid.raw_display.Screen()
        self.screen.register_palette(self.palette)
        self.loop = MainLoop(self.frame_widget, unhandled_input=self.handle_input,
                             screen = self.screen,
                             event_loop = evloop)
        self.loop.set_alarm_in(0.1, lambda loop, _: loop.draw_screen())

        self.loop.start()

        # The loggers get a Handler that writes to the screen. We want this to only
        # happen if the screen exists, so de-register them after the reactor stops.
        reactor.addSystemEventTrigger('after','startup', self.register_loggers)
        reactor.addSystemEventTrigger('before','shutdown', self.unregister_loggers)
        reactor.run()
        
        # We might have stopped the screen already, and the stop() method
        # doesn't check for stopping twice.
        if self.called_loop_stop:
            self.logger.warn('Internal error!')
        else:
            self.loop.stop()
            self.called_loop_stop = True

    @fail_safely
    def handle_input(self, key):
        if key == 'enter':
            text = self.edit_widget.edit_text
            if text in ['q', 'Q']:
                self.handle_quit_request()
            else:
                self.quit_flag = False

                try:
                    i = int(text)
                except ValueError:
                    i = None
                    self.handle_invalid_choice(text)

                if i is not None:
                    self.handle_choice(i)

            self.edit_widget.set_edit_text('')

    def _roll_write(self, line, attr=None):
        """Add a line to the roll with palette attributes 'attr'.

        If no attr is specified, None is used.

        Default attr is plain text
        """
        text = Text((attr, '* ' + line))
            
        self.roll_list.append(text)
        self.roll_list.set_focus(len(self.roll_list)-1)
        self._modified()

    @fail_safely
    def update_state(self, state):
        """Sets the game state window via one large string.
        """
        self.logger.debug('Drawing game state.')
        self.state_text[:] = [self.colorize(s) for s in state.split('\n')]
        self._modified()

    @fail_safely
    def update_game_log(self, log):
        """Sets the game log window via one large string.
        """
        self.logger.debug('Drawing game log.')
        self.game_log_list[:] = [self.colorize(s) for s in log.split('\n')]
        self.game_log_list.set_focus(len(self.game_log_list)-1)
        self._modified()

    @fail_safely
    def update_choices(self, choices):
        """Update choices list.
        """
        self.choices_list[:] = [self.colorize(str(c)) for c in choices]
        self._modified()

        length = len([c for c in choices if c[2] == '['])
        i = randint(1,length) if length else 0
        self.choices_list.append(self.colorize('\nPicking random choice: {0} in 1s'.format(i)))
        self._modified()
        #from twisted.internet import reactor
        #reactor.callLater(1, self.handle_choice, i)

    @fail_safely
    def update_prompt(self, prompt):
        """Set the prompt for the input field.
        """
        self.edit_widget.set_caption(prompt)
        self._modified()


    def _modified(self):
        if self.loop:
            self.loop.draw_screen()


    @fail_safely
    def quit(self):
        """Quit the program.
        """
        #import pdb; pdb.set_trace()
        #raise TypeError('Artificial TypeError')
        raise urwid.ExitMainLoop()

    def handle_invalid_choice(self, s):
        if len(s):
            text = 'Invalid choice: "' + s + '". Please enter an integer.'
            self.logger.warn(text)

    def handle_quit_request(self):
        if True or self.quit_flag:
            self.quit()
        else:
            self.quit_flag = True
            text = 'Are you sure you want to quit? Press Q again to confirm.'
            self.logger.warn(text)

    def handle_choice(self, i):
        if self.choice_callback:
            self.choice_callback(i)


    def colorize(self, s):
        """Applies color to roles found in a string.

        A string with attributes applied looks like

        Text([('attr1', 'some text'), 'some more text'])

        so we need to split into a list of tuples of text.
        """
        regex_color_dict = {
              r'\b([Ll]egionaries|[Ll]egionary|[Ll]eg|LEGIONARIES|LEGIONARY|LEG)\b' : 'brick',
              r'\b([Ll]aborers?|[Ll]ab|LABORERS?|LAB)\b' : 'rubble',
              r'\b([Cc]raftsmen|[Cc]raftsman|[Cc]ra|CRAFTSMEN|CRAFTSMAN|CRA)\b' : 'wood',
              r'\b([Aa]rchitects?|[Aa]rc|ARCHITECTS?|ARC)\b' : 'concrete',
              r'\b([Mm]erchants?|[Mm]er|MERCHANTS?|MER)\b' : 'stone',
              r'\b([Pp]atrons?|[Pp]at|PATRONS?|PAT)\b' : 'marble',
              r'\b([Jj]acks?|JACKS?)\b' : 'jack',

              r'\b([Bb]ricks?|[Bb]ri|BRICKS?|BRI)\b' : 'brick',
              r'\b([Rr]ubble|[Rr]ub|RUBBLE|RUB)\b' : 'rubble',
              r'\b([Ww]ood|[Ww]oo|WOOD|WOO)\b' : 'wood',
              r'\b([Cc]oncrete|[Cc]on|CONCRETE|CON)\b' : 'concrete',
              r'\b([Ss]tone|[Ss]to|STONE|STO)\b' : 'stone',
              r'\b([Mm]arble|[Mm]ar|MARBLE|MAR)\b' : 'marble',
        }

        def _colorize(s, regex, attr):
            """s is a tuple of ('attr', 'text'). This splits based on the regex
            and adds attr to any matches. Returns a list of tuples

            [('attr1', 'text1'), ('attr2', 'text2'), ('attr3','text3')]

            with some attributes being None if they aren't colored.
            """
            output = []
            a, t = s
            # Make a list of all tokens, split by matches
            tokens = re.split(regex, t)
            for tok in tokens:
                m = re.match(regex, tok)
                if m:
                    # matches get the new attributes
                    output.append( (attr,tok) )
                else:
                    # non-matches keep the old ones
                    output.append( (a, tok) )

            return output


        output = [ (None, s) ] 
        
        for k,v in regex_color_dict.items():
            new_output = []
            for token in output:
                new_output.extend(_colorize(token, k, v))

            output[:] = new_output

        return Text(output)
Esempio n. 6
0
class Tab(object):

	__metaclass__ = MetaSignals
	signals = ["child_added", "child_removed", "remove", "connected"]

	_valid_stati = [
		"informative",
		"actions", "actions_highlight","actions_own",
		"messages","messages_highlight","messages_own"]

	def __repr__(self):
		return "<tab: %s:%s:%s>" % (
			type(self).__name__, self._parent, self.name)

	def __str__(self):
		return self.name

	# Properties

	@types(switch = bool)
	def set_connected(self, switch):
		self._connected = switch

		for child in self.children:
			child.set_connected(switch)

		urwid.emit_signal(self, "connected", switch)

	connected = property(lambda x: x._connected, set_connected)

	def set_input_text(self, text):
		self._input_text = text

	input_text = property(lambda x: x._input_text, set_input_text)

	# Methods

	@types(name = (String, str, unicode))
	def __init__(self, name):
		self.name = name

		self._connected = False
		self._parent = None

		self.status = {}
		self.children = []
		self.input_history = None
		self.output_walker = SimpleListWalker([])
		self.input_text = ""
		self.auto_scroll = True

		self.read_line_index = -1

	def set_readline(self):
		if self.read_line_index != -1:
			try:
				del self.output_walker[self.read_line_index]
			except IndexError:
				pass

		line = Text("-"*30)
		line.set_align_mode ("center")
		self.output_walker.append(line)
		self.read_line_index = len(self.output_walker)-1

	def child_added(self, child):
		urwid.emit_signal(self, "child_added", self, child)
		child.set_connected(self.connected)
		self.children.append(child)

	def child_removed(self, child):
		urwid.emit_signal(self, "child_removed", self, child)
		try:
			i = self.children.index(child)
		except ValueError:
			pass
		else:
			del self.children[i]

	def set_parent(self, parent):
		if parent in self.children:
			print "Loop detected in '%s'.set_parent(%s)" % (
				self, parent)
			return

		try:
			self._parent.child_removed(self)
		except AttributeError:
			pass

		self._parent = parent

		try:
			self._parent.child_added(self)
		except AttributeError:
			pass

	parent = property(lambda x: x._parent, set_parent)

	def remove(self):
		""" emit remove signals """
		for child in self.children:
			child.remove()
			self.child_removed(child)
		urwid.emit_signal(self, "remove")
		self.set_parent(None)

	@types(name = str)
	def add_status(self, name):
		if name in self._valid_stati:
			self.status[name] = True

	@types(status = str)
	def has_status(self, status):
		return self.status.has_key(status)

	@types(name = str)
	def remove_status(self, name):
		try:
			del self.status[name]
		except KeyError:
			pass

	def reset_status(self):
		self.status = {}

	def print_last_log(self, lines=0):
		"""	Fetch the given amount of lines of history for
			the channel on the given server and print it to the
			channel's textview.
		"""
		lines = UInt64(lines or config.get(
			"chatting",
			"last_log_lines",
			"0"))

		if type(self) == Server:
			server = self.name
			channel = ""
		else:
			server = self.parent.name
			channel = self.name

		for line in connection.sushi.log(server, channel, lines):
			self.output_walker.append(Text(unicode(line)))