示例#1
0
class Display(object):
    lifetime = 5 # seconds
    
    def __init__(self, palette=None):
        # A screen is useful to have right away
        self.screen = Screen()
        if palette is None:
            palette = gui.GUI.palette
        self.screen.register_palette(palette)

    def setWidget(self, widget, useFiller=False):
        def possiblyQuit(key):
            if key in ('q', 'Q'):
                reactor.stop()

        # The widget under test is outline, possibly padded with filler
        outlined = u.LineBox(widget)
        if useFiller:
            height = 'flow' if hasattr(widget, 'rows') else 3
            w = u.Filler(outlined, valign='top', height=height)
        else:
            w = outlined
        main = u.WidgetWrap(w)
        # The loops
        eventLoop = u.TwistedEventLoop(reactor, manage_reactor=False)
        self.loop = u.MainLoop(
            main, screen=self.screen,
            unhandled_input=possiblyQuit,
            event_loop=eventLoop)
        self.loop.start()

    def width(self):
        return self.screen.get_cols_rows()[0] - 2
        
    def update(self):
        self.loop.draw_screen()

    def stop(self):
        self.screen.unhook_event_loop(self.loop)
        self.loop.stop()
示例#2
0
class GUI(object):
    """
    I am the main curses interface.
    """
    title = "Logalyzer"
    
    palette = [
        # Name
        # 'fg color,setting', 'background color', 'mono setting'
        ('heading',
         'dark cyan', 'default', 'default'),
        ('heading_current',
         'light cyan,underline', 'default', 'underline'),
        ('message',
         'white', 'default', 'default'),
        ('error_label',
         'light red,underline', 'default', 'underline'),
        ('error',
         'brown', 'default', 'default'),
        ('warning_label',
         'yellow,underline', 'default', 'underline'),
        ('warning',
         'brown', 'default', 'default'),
    ]
    
    def __init__(self, stopperFunction):
        """Constructor"""
        self.running = False
        self.stopperFunction = stopperFunction
        self.id_counter = 0
        # A screen is useful right away
        self.screen = Screen()
        self.screen.register_palette(self.palette)
        self.screen.set_mouse_tracking(True)

    def start(self, fileNames):
        """
        Constructs my widgets and starts my event loop and main loop.
        """
        def possiblyQuit(key):
            if key in ('q', 'Q'):
                if not hasattr(self, '_stopping'):
                    self._stopping = None
                    self.warning("Shutting down, please wait...")
                    if reactor.running:
                        # I trust the stopper function to call my stop
                        # method at the appropriate time
                        reactor.callFromThread(reactor.stop)
                
        # The top-level widgets
        self.m = Messages()
        self.f = Files(fileNames, self._dims()[0])
        p = u.Pile([u.Divider("=", 1, 1), self.f, u.Divider(" ")])
        main = u.WidgetWrap(
            u.LineBox(
                u.Padding(
                    u.Frame(self.m, footer=p),
                    left=1, right=1),
                title=self.title))
        eventLoop = u.TwistedEventLoop(reactor, manage_reactor=False)
        self.formerDims = self._dims()
        self.loop = u.MainLoop(
            main, screen=self.screen,
            unhandled_input=possiblyQuit, event_loop=eventLoop)
        reactor.addSystemEventTrigger('after', 'shutdown', self.stop)
        #sys.stdout = StdSubstitute('STDOUT', self)
        sys.stderr = observer = StdSubstitute('STDERR', self)
        twisted.python.log.addObserver(observer)
        self.running = True
        self.loop.start()
    
    def _dims(self):
        # Deduct 4 from each dimension due to outline and padding
        return [x-4 for x in self.screen.get_cols_rows()]

    def update(self):
        """
        Updates my display, possibly with an updated screen width.
        """
        if not self.running:
            return
        width, height = self._dims()
        # Update for new width
        if width != self.formerDims[0]:
            self.f.updateWidth(width)
        self.loop.draw_screen()

    def stop(self):
        """
        Tears down the GUI display. This will be called by
        L{main.Recorder.shutdown} after all other shutdown steps are
        done, as part of the Twisted reactor shutdown.
        """
        if self.running and not hasattr(self, '_shutdownFlag'):
            self._shutdownFlag = None
            self.running = False
            self.screen.unhook_event_loop(self.loop)
            self.loop.stop()
    
    def msgHeading(self, textProto, *args):
        """
        Sends a new heading to my scrolling message window. You can supply
        a single string, or a string prototype followed by one or more
        formatting arguments.

        Returns a unique integer ID for this heading. Use that when
        supplying lines of message body under this heading.
        """
        self.id_counter += 1
        ID = self.id_counter
        self.m.heading(textProto.format(*args), ID)
        self.update()
        return ID

    def msgBody(self, ID, textProto, *args):
        """
        Adds a new line of message body under heading ID. You can supply a
        single string after the integer ID, or a string prototype
        followed by one or more formatting arguments.
        """
        text = textProto.format(*args)
        self.m.msg(text, ID)
        self.update()

    def msgOrphan(self, textProto, *args):
        """
        Adds a new line of message body under a (possibly blank) orphan
        heading ID. You can supply a single string, or a string
        prototype followed by one or more formatting arguments.
        """
        text = textProto.format(*args)
        self.m.msg(text)
        self.update()

    def warning(self, textProto, *args):
        """
        Adds a distinctive warning message to the message window.
        """
        self.m.distinctMsg('warning', textProto.format(*args))
        self.update()
        
    def error(self, textProto, *args):
        """
        Adds a distinctive error message to the message window.
        """
        self.m.distinctMsg('error', textProto.format(*args))
        self.update()

    def msgProgress(self, ID, N):
        self.m.progress(ID, N)
        self.update()
        
    def fileStatus(self, fileName, *args):
        """
        Updates the status entry for the specified fileName. With no
        further arguments, the progress indicator for the file is
        given a spin. With a string or string prototype followed by
        formatting arguments, the progress indicator is reset and the
        brief status text following the filename is updated.
        """
        if args:
            self.f.setStatus(fileName, *args)
        else:
            self.f.indicator(fileName)
        self.update()