~certify-web-dev/twisted/certify-staging

« back to all changes in this revision

Viewing changes to twisted/manhole/ui/pywidgets.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2010-01-02 19:38:17 UTC
  • mfrom: (2.2.4 sid)
  • Revision ID: james.westby@ubuntu.com-20100102193817-jphp464ppwh7dulg
Tags: 9.0.0-1
* python-twisted: Depend on the python-twisted-* 9.0 packages.
* python-twisted: Depend on python-zope.interface only. Closes: #557781.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
# System Imports
3
 
import code, string, sys, traceback
4
 
import gtk
5
 
True = 1
6
 
False = 0
7
 
 
8
 
# Twisted Imports
9
 
from twisted.spread.ui import gtkutil
10
 
from twisted.python import util
11
 
rcfile = util.sibpath(__file__, 'gtkrc')
12
 
gtk.rc_parse(rcfile)
13
 
 
14
 
 
15
 
def isCursorOnFirstLine(entry):
16
 
    firstnewline = string.find(entry.get_chars(0,-1), '\n')
17
 
    if entry.get_point() <= firstnewline or firstnewline == -1:
18
 
        return 1
19
 
 
20
 
def isCursorOnLastLine(entry):
21
 
    if entry.get_point() >= string.rfind(string.rstrip(entry.get_chars(0,-1)), '\n'):
22
 
        return 1
23
 
 
24
 
 
25
 
class InputText(gtk.GtkText):
26
 
    linemode = 0
27
 
    blockcount = 0
28
 
 
29
 
    def __init__(self, toplevel=None):
30
 
        gtk.GtkText.__init__(self)
31
 
        self['name'] = 'Input'
32
 
        self.set_editable(gtk.TRUE)
33
 
        self.connect("key_press_event", self.processKey)
34
 
        #self.set_word_wrap(gtk.TRUE)
35
 
 
36
 
        self.history = []
37
 
        self.histpos = 0
38
 
 
39
 
        if toplevel:
40
 
            self.toplevel = toplevel
41
 
 
42
 
    def historyUp(self):
43
 
        if self.histpos > 0:
44
 
            self.histpos = self.histpos - 1
45
 
            self.delete_text(0, -1)
46
 
            self.insert_defaults(self.history[self.histpos])
47
 
            self.set_position(0)
48
 
 
49
 
    def historyDown(self):
50
 
        if self.histpos < len(self.history) - 1:
51
 
            self.histpos = self.histpos + 1
52
 
            self.delete_text(0, -1)
53
 
            self.insert_defaults(self.history[self.histpos])
54
 
        elif self.histpos == len(self.history) - 1:
55
 
            self.histpos = self.histpos + 1
56
 
            self.delete_text(0, -1)
57
 
 
58
 
    def processKey(self, entry, event):
59
 
        # TODO: make key bindings easier to customize.
60
 
 
61
 
        stopSignal = False
62
 
        # ASSUMPTION: Assume Meta == mod4
63
 
        isMeta = event.state & gtk.GDK.MOD4_MASK
64
 
        if event.keyval == gtk.GDK.Return:
65
 
            isShift = event.state & gtk.GDK.SHIFT_MASK
66
 
            if isShift:
67
 
                self.linemode = True
68
 
                self.insert_defaults('\n')
69
 
            else:
70
 
                stopSignal = True
71
 
                text = self.get_chars(0,-1)
72
 
                if not text: return
73
 
                try:
74
 
                    if text[0] == '/':
75
 
                        # It's a local-command, don't evaluate it as
76
 
                        # Python.
77
 
                        c = True
78
 
                    else:
79
 
                        # This will tell us it's a complete expression.
80
 
                        c = code.compile_command(text)
81
 
                except SyntaxError, e:
82
 
                    # Ding!
83
 
                    self.set_positionLineOffset(e.lineno, e.offset)
84
 
                    print "offset", e.offset
85
 
                    errmsg = {'traceback': [],
86
 
                              'exception': [str(e) + '\n']}
87
 
                    self.toplevel.output.console([('exception', errmsg)])
88
 
                except OverflowError, e:
89
 
                    e = traceback.format_exception_only(OverflowError, e)
90
 
                    errmsg = {'traceback': [],
91
 
                              'exception': e}
92
 
                    self.toplevel.output.console([('exception', errmsg)])
93
 
                else:
94
 
                    if c is None:
95
 
                        self.linemode = True
96
 
                        stopSignal = False
97
 
                    else:
98
 
                        self.sendMessage(entry)
99
 
                        self.clear()
100
 
 
101
 
        elif ((event.keyval == gtk.GDK.Up and isCursorOnFirstLine(self))
102
 
              or (isMeta and event.string == 'p')):
103
 
            self.historyUp()
104
 
            stopSignal = True
105
 
        elif ((event.keyval == gtk.GDK.Down and isCursorOnLastLine(self))
106
 
              or (isMeta and event.string == 'n')):
107
 
            self.historyDown()
108
 
            stopSignal = True
109
 
 
110
 
        if stopSignal:
111
 
            self.emit_stop_by_name("key_press_event")
112
 
            return True
113
 
 
114
 
    def clear(self):
115
 
        self.delete_text(0, -1)
116
 
        self.linemode = False
117
 
 
118
 
    def set_positionLineOffset(self, line, offset):
119
 
        text = self.get_chars(0, -1)
120
 
        pos = 0
121
 
        for l in xrange(line - 1):
122
 
            pos = string.index(text, '\n', pos) + 1
123
 
        pos = pos + offset - 1
124
 
        self.set_position(pos)
125
 
 
126
 
    def sendMessage(self, unused_data=None):
127
 
        text = self.get_chars(0,-1)
128
 
        if self.linemode:
129
 
            self.blockcount = self.blockcount + 1
130
 
            fmt = ">>> # begin %s\n%%s\n#end %s\n" % (
131
 
                self.blockcount, self.blockcount)
132
 
        else:
133
 
            fmt = ">>> %s\n"
134
 
        self.history.append(text)
135
 
        self.histpos = len(self.history)
136
 
        self.toplevel.output.console([['command',fmt % text]])
137
 
        self.toplevel.codeInput(text)
138
 
 
139
 
 
140
 
    def readHistoryFile(self, filename=None):
141
 
        if filename is None:
142
 
            filename = self.historyfile
143
 
 
144
 
        f = open(filename, 'r', 1)
145
 
        self.history.extend(f.readlines())
146
 
        f.close()
147
 
        self.histpos = len(self.history)
148
 
 
149
 
    def writeHistoryFile(self, filename=None):
150
 
        if filename is None:
151
 
            filename = self.historyfile
152
 
 
153
 
        f = open(filename, 'a', 1)
154
 
        f.writelines(self.history)
155
 
        f.close()
156
 
 
157
 
 
158
 
class Interaction(gtk.GtkWindow):
159
 
    titleText = "Abstract Python Console"
160
 
 
161
 
    def __init__(self):
162
 
        gtk.GtkWindow.__init__(self, gtk.WINDOW_TOPLEVEL)
163
 
        self.set_title(self.titleText)
164
 
        self.set_default_size(300, 300)
165
 
        self.set_name("Manhole")
166
 
 
167
 
        vbox = gtk.GtkVBox()
168
 
        pane = gtk.GtkVPaned()
169
 
 
170
 
        self.output = OutputConsole(toplevel=self)
171
 
        pane.pack1(gtkutil.scrollify(self.output), gtk.TRUE, gtk.FALSE)
172
 
 
173
 
        self.input = InputText(toplevel=self)
174
 
        pane.pack2(gtkutil.scrollify(self.input), gtk.FALSE, gtk.TRUE)
175
 
        vbox.pack_start(pane, 1,1,0)
176
 
 
177
 
        self.add(vbox)
178
 
        self.input.grab_focus()
179
 
 
180
 
    def codeInput(self, text):
181
 
        raise NotImplementedError("Bleh.")
182
 
 
183
 
 
184
 
class LocalInteraction(Interaction):
185
 
    titleText = "Local Python Console"
186
 
    def __init__(self):
187
 
        Interaction.__init__(self)
188
 
        self.globalNS = {}
189
 
        self.localNS = {}
190
 
        self.filename = "<gtk console>"
191
 
 
192
 
    def codeInput(self, text):
193
 
        from twisted.manhole.service import runInConsole
194
 
        val = runInConsole(text, self.output.console,
195
 
                           self.globalNS, self.localNS, self.filename)
196
 
        if val is not None:
197
 
            self.localNS["_"] = val
198
 
            self.output.console([("result", repr(val) + "\n")])
199
 
 
200
 
class OutputConsole(gtk.GtkText):
201
 
    maxBufSz = 10000
202
 
 
203
 
    def __init__(self, toplevel=None):
204
 
        gtk.GtkText.__init__(self)
205
 
        self['name'] = "Console"
206
 
        gtkutil.defocusify(self)
207
 
        #self.set_word_wrap(gtk.TRUE)
208
 
 
209
 
        if toplevel:
210
 
            self.toplevel = toplevel
211
 
 
212
 
    def console(self, message):
213
 
        self.set_point(self.get_length())
214
 
        self.freeze()
215
 
        previous_kind = None
216
 
        style = self.get_style()
217
 
        style_cache = {}
218
 
        try:
219
 
            for element in message:
220
 
                if element[0] == 'exception':
221
 
                    s = traceback.format_list(element[1]['traceback'])
222
 
                    s.extend(element[1]['exception'])
223
 
                    s = string.join(s, '')
224
 
                else:
225
 
                    s = element[1]
226
 
 
227
 
                if element[0] != previous_kind:
228
 
                    style = style_cache.get(element[0], None)
229
 
                    if style is None:
230
 
                        gtk.rc_parse_string(
231
 
                            'widget \"Manhole.*.Console\" '
232
 
                            'style \"Console_%s\"\n'
233
 
                            % (element[0]))
234
 
                        self.set_rc_style()
235
 
                        style_cache[element[0]] = style = self.get_style()
236
 
                # XXX: You'd think we'd use style.bg instead of 'None'
237
 
                # here, but that doesn't seem to match the color of
238
 
                # the backdrop.
239
 
                self.insert(style.font, style.fg[gtk.STATE_NORMAL],
240
 
                            None, s)
241
 
                previous_kind = element[0]
242
 
            l = self.get_length()
243
 
            diff = self.maxBufSz - l
244
 
            if diff < 0:
245
 
                diff = - diff
246
 
                self.delete_text(0,diff)
247
 
        finally:
248
 
            self.thaw()
249
 
        a = self.get_vadjustment()
250
 
        a.set_value(a.upper - a.page_size)