~ntt-pf-lab/nova/monkey_patch_notification

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/doc/words/examples/cursesclient.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
# Copyright (c) 2009 Twisted Matrix Laboratories.
 
4
# See LICENSE for details.
 
5
 
 
6
"""
 
7
This is an example of integrating curses with the twisted underlying    
 
8
select loop. Most of what is in this is insignificant -- the main piece 
 
9
of interest is the 'CursesStdIO' class.                                 
 
10
 
 
11
This class acts as file-descriptor 0, and is scheduled with the twisted
 
12
select loop via reactor.addReader (once the curses class extends it
 
13
of course). When there is input waiting doRead is called, and any
 
14
input-oriented curses calls (ie. getch()) should be executed within this
 
15
block.
 
16
 
 
17
Remember to call nodelay(1) in curses, to make getch() non-blocking.
 
18
"""
 
19
 
 
20
# System Imports
 
21
import curses, time, traceback, sys
 
22
import curses.wrapper
 
23
 
 
24
# Twisted imports
 
25
from twisted.internet import reactor
 
26
from twisted.internet.protocol import ClientFactory
 
27
from twisted.words.protocols.irc import IRCClient
 
28
from twisted.python import log
 
29
 
 
30
class TextTooLongError(Exception):
 
31
    pass
 
32
 
 
33
class CursesStdIO:
 
34
    """fake fd to be registered as a reader with the twisted reactor.
 
35
       Curses classes needing input should extend this"""
 
36
 
 
37
    def fileno(self):
 
38
        """ We want to select on FD 0 """
 
39
        return 0
 
40
 
 
41
    def doRead(self):
 
42
        """called when input is ready"""
 
43
 
 
44
    def logPrefix(self): return 'CursesClient'
 
45
 
 
46
 
 
47
class IRC(IRCClient):
 
48
 
 
49
    """ A protocol object for IRC """
 
50
 
 
51
    nickname = "testcurses"
 
52
 
 
53
    def __init__(self, screenObj):
 
54
        # screenObj should be 'stdscr' or a curses window/pad object
 
55
        self.screenObj = screenObj
 
56
        # for testing (hacky way around initial bad design for this example) :)
 
57
        self.screenObj.irc = self
 
58
 
 
59
    def lineReceived(self, line):
 
60
        """ When receiving a line, add it to the output buffer """
 
61
        self.screenObj.addLine(line)
 
62
 
 
63
    def connectionMade(self):
 
64
        IRCClient.connectionMade(self)
 
65
        self.screenObj.addLine("* CONNECTED")
 
66
 
 
67
    def clientConnectionLost(self, connection, reason):
 
68
        pass
 
69
 
 
70
 
 
71
class IRCFactory(ClientFactory):
 
72
 
 
73
    """
 
74
    Factory used for creating IRC protocol objects 
 
75
    """
 
76
 
 
77
    protocol = IRC
 
78
 
 
79
    def __init__(self, screenObj):
 
80
        self.irc = self.protocol(screenObj)
 
81
 
 
82
    def buildProtocol(self, addr=None):
 
83
        return self.irc
 
84
 
 
85
    def clientConnectionLost(self, conn, reason):
 
86
        pass
 
87
 
 
88
 
 
89
class Screen(CursesStdIO):
 
90
    def __init__(self, stdscr):
 
91
        self.timer = 0
 
92
        self.statusText = "TEST CURSES APP -"
 
93
        self.searchText = ''
 
94
        self.stdscr = stdscr
 
95
 
 
96
        # set screen attributes
 
97
        self.stdscr.nodelay(1) # this is used to make input calls non-blocking
 
98
        curses.cbreak()
 
99
        self.stdscr.keypad(1)
 
100
        curses.curs_set(0)     # no annoying mouse cursor
 
101
 
 
102
        self.rows, self.cols = self.stdscr.getmaxyx()
 
103
        self.lines = []
 
104
 
 
105
        curses.start_color()
 
106
 
 
107
        # create color pair's 1 and 2
 
108
        curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
 
109
        curses.init_pair(2, curses.COLOR_CYAN, curses.COLOR_BLACK)
 
110
 
 
111
        self.paintStatus(self.statusText)
 
112
 
 
113
    def connectionLost(self, reason):
 
114
        self.close()
 
115
 
 
116
    def addLine(self, text):
 
117
        """ add a line to the internal list of lines"""
 
118
 
 
119
        self.lines.append(text)
 
120
        self.redisplayLines()
 
121
 
 
122
    def redisplayLines(self):
 
123
        """ method for redisplaying lines 
 
124
            based on internal list of lines """
 
125
 
 
126
        self.stdscr.clear()
 
127
        self.paintStatus(self.statusText)
 
128
        i = 0
 
129
        index = len(self.lines) - 1
 
130
        while i < (self.rows - 3) and index >= 0:
 
131
            self.stdscr.addstr(self.rows - 3 - i, 0, self.lines[index], 
 
132
                               curses.color_pair(2))
 
133
            i = i + 1
 
134
            index = index - 1
 
135
        self.stdscr.refresh()
 
136
 
 
137
    def paintStatus(self, text):
 
138
        if len(text) > self.cols: raise TextTooLongError
 
139
        self.stdscr.addstr(self.rows-2,0,text + ' ' * (self.cols-len(text)), 
 
140
                           curses.color_pair(1))
 
141
        # move cursor to input line
 
142
        self.stdscr.move(self.rows-1, self.cols-1)
 
143
 
 
144
    def doRead(self):
 
145
        """ Input is ready! """
 
146
        curses.noecho()
 
147
        self.timer = self.timer + 1
 
148
        c = self.stdscr.getch() # read a character
 
149
 
 
150
        if c == curses.KEY_BACKSPACE:
 
151
            self.searchText = self.searchText[:-1]
 
152
 
 
153
        elif c == curses.KEY_ENTER or c == 10:
 
154
            self.addLine(self.searchText)
 
155
            # for testing too
 
156
            try: self.irc.sendLine(self.searchText)
 
157
            except: pass
 
158
            self.stdscr.refresh()
 
159
            self.searchText = ''
 
160
 
 
161
        else:
 
162
            if len(self.searchText) == self.cols-2: return
 
163
            self.searchText = self.searchText + chr(c)
 
164
 
 
165
        self.stdscr.addstr(self.rows-1, 0, 
 
166
                           self.searchText + (' ' * (
 
167
                           self.cols-len(self.searchText)-2)))
 
168
        self.stdscr.move(self.rows-1, len(self.searchText))
 
169
        self.paintStatus(self.statusText + ' %d' % len(self.searchText))
 
170
        self.stdscr.refresh()
 
171
 
 
172
    def close(self):
 
173
        """ clean up """
 
174
 
 
175
        curses.nocbreak()
 
176
        self.stdscr.keypad(0)
 
177
        curses.echo()
 
178
        curses.endwin()
 
179
 
 
180
if __name__ == '__main__':
 
181
    stdscr = curses.initscr() # initialize curses
 
182
    screen = Screen(stdscr)   # create Screen object
 
183
    stdscr.refresh()
 
184
    ircFactory = IRCFactory(screen)
 
185
    reactor.addReader(screen) # add screen object as a reader to the reactor
 
186
    reactor.connectTCP("irc.freenode.net",6667,ircFactory) # connect to IRC
 
187
    reactor.run() # have fun!
 
188
    screen.close()