summaryrefslogtreecommitdiffstats
path: root/Mac/Contrib/PyIDE-src/IDELib/Widgets/PyDebugger.py
diff options
context:
space:
mode:
Diffstat (limited to 'Mac/Contrib/PyIDE-src/IDELib/Widgets/PyDebugger.py')
-rw-r--r--Mac/Contrib/PyIDE-src/IDELib/Widgets/PyDebugger.py880
1 files changed, 880 insertions, 0 deletions
diff --git a/Mac/Contrib/PyIDE-src/IDELib/Widgets/PyDebugger.py b/Mac/Contrib/PyIDE-src/IDELib/Widgets/PyDebugger.py
new file mode 100644
index 0000000..c1f5ce0
--- /dev/null
+++ b/Mac/Contrib/PyIDE-src/IDELib/Widgets/PyDebugger.py
@@ -0,0 +1,880 @@
+import sys
+import bdb
+import types
+import os
+
+import W
+import WASTEconst
+import PyBrowser
+import Qd
+import Evt
+import Lists
+import MacOS
+_filenames = {}
+
+SIMPLE_TYPES = (
+ types.NoneType,
+ types.IntType,
+ types.LongType,
+ types.FloatType,
+ types.ComplexType,
+ types.StringType
+)
+
+
+class Debugger(bdb.Bdb):
+
+ def __init__(self, title = 'Debugger'):
+ bdb.Bdb.__init__(self)
+ self.closed = 1
+ self.title = title
+ self.breaksviewer = None
+ self.reset()
+ self.tracing = 0
+ self.tracingmonitortime = Evt.TickCount()
+
+ prefs = W.getapplication().getprefs()
+ if prefs.debugger:
+ self.breaks = prefs.debugger.breaks
+ self.bounds, self.horpanes, self.verpanes = prefs.debugger.windowsettings
+ self.tracemagic = prefs.debugger.tracemagic
+ for key in self.breaks.keys():
+ if key[:1] == '<' and key[-1:] == '>':
+ del self.breaks[key]
+ else:
+ self.breaks = {}
+ self.horpanes = (0.4, 0.6)
+ self.verpanes = (0.3, 0.35, 0.35)
+ self.bounds = (600, 400)
+ self.tracemagic = 0
+ self.laststacksel = None
+ self.editors = {}
+
+ def reset(self):
+ self.currentframe = None
+ self.file = None
+ self.laststack = None
+ self.reason = 'Not running'
+ self.continuewithoutdebugger = 0
+ bdb.Bdb.reset(self)
+ self.forget()
+
+ def start(self, bottomframe = None, running = 0):
+ W.getapplication().DebuggerQuit = bdb.BdbQuit
+ import Menu
+ Menu.HiliteMenu(0)
+ if self.closed:
+ self.setupwidgets(self.title)
+ self.closed = 0
+ if not self.w.parent.debugger_quitting:
+ self.w.select()
+ raise W.AlertError, 'There is another debugger session busy.'
+ self.reset()
+ self.botframe = bottomframe
+ if running:
+ self.set_continue()
+ self.reason = 'RunningŠ'
+ self.setstate('running')
+ else:
+ self.set_step()
+ self.reason = 'stopped'
+ self.setstate('stopped')
+ sys.settrace(self.trace_dispatch)
+
+ def stop(self):
+ self.set_quit()
+ if self.w.parent:
+ self.exit_mainloop()
+ self.resetwidgets()
+
+ def set_continue_without_debugger(self):
+ sys.settrace(None)
+ self.set_quit()
+ self.clear_tracefuncs()
+ self.continuewithoutdebugger = 1
+ if self.w.parent:
+ self.exit_mainloop()
+ self.resetwidgets()
+
+ def clear_tracefuncs(self):
+ try:
+ raise 'spam'
+ except:
+ pass
+ frame = sys.exc_traceback.tb_frame
+ while frame is not None:
+ del frame.f_trace
+ frame = frame.f_back
+
+ def postmortem(self, exc_type, exc_value, traceback):
+ if self.closed:
+ self.setupwidgets(self.title)
+ self.closed = 0
+ if not self.w.parent.debugger_quitting:
+ raise W.AlertError, 'There is another debugger session busy.'
+ self.reset()
+ if traceback:
+ self.botframe = traceback.tb_frame
+ while traceback.tb_next <> None:
+ traceback = traceback.tb_next
+ frame = traceback.tb_frame
+ else:
+ self.botframe = None
+ frame = None
+ self.w.panes.bottom.buttons.killbutton.enable(1)
+ self.reason = '(dead) ' + self.formatexception(exc_type, exc_value)
+ self.w.select()
+ self.setup(frame, traceback)
+ self.setstate('dead')
+ self.showstack(self.curindex)
+ self.showframe(self.curindex)
+
+ def setupwidgets(self, title):
+ self.w = w = W.Window(self.bounds, title, minsize = (500, 300))
+
+ w.panes = W.HorizontalPanes((8, 4, -8, -8), self.horpanes)
+
+ w.panes.browserpanes = browserpanes = W.VerticalPanes(None, self.verpanes)
+
+ browserpanes.stacklist = W.Group(None)
+ browserpanes.stacklist.title = W.TextBox((4, 0, 0, 12), 'Stack')
+ browserpanes.stacklist.stack = W.List((0, 16, 0, 0), callback = self.do_stack, flags = Lists.lOnlyOne)
+
+ browserpanes.locals = W.Group(None)
+ browserpanes.locals.title = W.TextBox((4, 0, 0, 12), 'Local variables')
+ browserpanes.locals.browser = PyBrowser.BrowserWidget((0, 16, 0, 0))
+
+ browserpanes.globals = W.Group(None)
+ browserpanes.globals.title = W.TextBox((4, 0, 0, 12), 'Global variables')
+ browserpanes.globals.browser = PyBrowser.BrowserWidget((0, 16, 0, 0))
+
+ w.panes.bottom = bottom = W.Group(None)
+ bottom.src = src = W.Group((0, 52, 0, 0))
+ source = SourceViewer((1, 1, -15, -15), readonly = 1, debugger = self)
+ src.optionsmenu = W.PopupMenu((-16, 0, 16, 16), [])
+ src.optionsmenu.bind('<click>', self.makeoptionsmenu)
+
+ src._barx = W.Scrollbar((0, -16, -15, 16), source.hscroll, max = 32767)
+ src._bary = W.Scrollbar((-16, 15, 16, -15), source.vscroll, max = 32767)
+ src.source = source
+ src.frame = W.Frame((0, 0, -15, -15))
+
+ bottom.tracingmonitor = TracingMonitor((0, 23, 6, 6))
+ bottom.state = W.TextBox((12, 20, 0, 16), self.reason)
+
+ bottom.srctitle = W.TextBox((12, 36, 0, 14))
+ bottom.buttons = buttons = W.Group((12, 0, 0, 16))
+
+ buttons.runbutton = W.Button((0, 0, 50, 16), "Run", self.do_run)
+ buttons.stopbutton = W.Button((58, 0, 50, 16), "Stop", self.do_stop)
+ buttons.killbutton = W.Button((116, 0, 50, 16), "Kill", self.do_kill)
+ buttons.line = W.VerticalLine((173, 0, 0, 0))
+ buttons.stepbutton = W.Button((181, 0, 50, 16), "Step", self.do_step)
+ buttons.stepinbutton = W.Button((239, 0, 50, 16), "Step in", self.do_stepin)
+ buttons.stepoutbutton = W.Button((297, 0, 50, 16), "Step out", self.do_stepout)
+
+ w.bind('cmdr', buttons.runbutton.push)
+ w.bind('cmd.', buttons.stopbutton.push)
+ w.bind('cmdk', buttons.killbutton.push)
+ w.bind('cmds', buttons.stepbutton.push)
+ w.bind('cmdt', buttons.stepinbutton.push)
+ w.bind('cmdu', buttons.stepoutbutton.push)
+
+ w.bind('<close>', self.close)
+
+ w.open()
+ w.xxx___select(w.panes.bottom.src.source)
+
+ def makeoptionsmenu(self):
+ options = [('Clear breakpoints', self.w.panes.bottom.src.source.clearbreakpoints),
+ ('Clear all breakpoints', self.clear_all_breaks),
+ ('Edit breakpointsŠ', self.edit_breaks), '-',
+ (self.tracemagic and
+ 'Disable __magic__ tracing' or 'Enable __magic__ tracing', self.togglemagic)]
+ self.w.panes.bottom.src.optionsmenu.set(options)
+
+ def edit_breaks(self):
+ if self.breaksviewer:
+ self.breaksviewer.select()
+ else:
+ self.breaksviewer = BreakpointsViewer(self)
+
+ def togglemagic(self):
+ self.tracemagic = not self.tracemagic
+
+ def setstate(self, state):
+ self.w.panes.bottom.tracingmonitor.reset()
+ self.w.panes.bottom.state.set(self.reason)
+ buttons = self.w.panes.bottom.buttons
+ if state == 'stopped':
+ buttons.runbutton.enable(1)
+ buttons.stopbutton.enable(0)
+ buttons.killbutton.enable(1)
+ buttons.stepbutton.enable(1)
+ buttons.stepinbutton.enable(1)
+ buttons.stepoutbutton.enable(1)
+ elif state == 'running':
+ buttons.runbutton.enable(0)
+ buttons.stopbutton.enable(1)
+ buttons.killbutton.enable(1)
+ buttons.stepbutton.enable(0)
+ buttons.stepinbutton.enable(0)
+ buttons.stepoutbutton.enable(0)
+ elif state == 'idle':
+ buttons.runbutton.enable(0)
+ buttons.stopbutton.enable(0)
+ buttons.killbutton.enable(0)
+ buttons.stepbutton.enable(0)
+ buttons.stepinbutton.enable(0)
+ buttons.stepoutbutton.enable(0)
+ elif state == 'dead':
+ buttons.runbutton.enable(0)
+ buttons.stopbutton.enable(0)
+ buttons.killbutton.enable(1)
+ buttons.stepbutton.enable(0)
+ buttons.stepinbutton.enable(0)
+ buttons.stepoutbutton.enable(0)
+ else:
+ print 'unknown state:', state
+
+ def resetwidgets(self):
+ self.reason = ''
+ self.w.panes.bottom.srctitle.set('')
+ self.w.panes.bottom.src.source.set('')
+ self.w.panes.browserpanes.stacklist.stack.set([])
+ self.w.panes.browserpanes.locals.browser.set({})
+ self.w.panes.browserpanes.globals.browser.set({})
+ self.setstate('idle')
+
+ # W callbacks
+
+ def close(self):
+ self.set_quit()
+ self.exit_mainloop()
+ self.closed = 1
+
+ self.unregister_editor(self.w.panes.bottom.src.source,
+ self.w.panes.bottom.src.source.file)
+ self.horpanes = self.w.panes.getpanesizes()
+ self.verpanes = self.w.panes.browserpanes.getpanesizes()
+ self.bounds = self.w.getbounds()
+ prefs = W.getapplication().getprefs()
+ prefs.debugger.breaks = self.breaks
+ prefs.debugger.windowsettings = self.bounds, self.horpanes, self.verpanes
+ prefs.debugger.tracemagic = self.tracemagic
+ prefs.save()
+
+ # stack list callback
+
+ def do_stack(self, isdbl):
+ sel = self.w.panes.browserpanes.stacklist.stack.getselection()
+ if isdbl:
+ if sel:
+ frame, lineno = self.stack[sel[0] + 1]
+ filename = frame.f_code.co_filename
+ editor = self.w._parentwindow.parent.openscript(filename, lineno)
+ if self.breaks.has_key(filename):
+ editor.showbreakpoints(1)
+ else:
+ if sel and sel <> self.laststacksel:
+ self.showframe(sel[0] + 1)
+ self.laststacksel = sel
+
+ def geteditor(self, filename):
+ if filename[:1] == '<' and filename[-1:] == '>':
+ editor = W.getapplication().getscript(filename[1:-1])
+ else:
+ editor = W.getapplication().getscript(filename)
+ return editor
+
+ # button callbacks
+
+ def do_run(self):
+ self.running()
+ self.set_continue()
+ self.exit_mainloop()
+
+ def do_stop(self):
+ self.set_step()
+
+ def do_kill(self):
+ self.set_quit()
+ self.exit_mainloop()
+ self.resetwidgets()
+
+ def do_step(self):
+ self.running()
+ self.set_next(self.curframe)
+ self.exit_mainloop()
+
+ def do_stepin(self):
+ self.running()
+ self.set_step()
+ self.exit_mainloop()
+
+ def do_stepout(self):
+ self.running()
+ self.set_return(self.curframe)
+ self.exit_mainloop()
+
+ def running(self):
+ W.SetCursor('watch')
+ self.reason = 'RunningŠ'
+ self.setstate('running')
+ #self.w.panes.bottom.src.source.set('')
+ #self.w.panes.browserpanes.stacklist.stack.set([])
+ #self.w.panes.browserpanes.locals.browser.set({})
+ #self.w.panes.browserpanes.globals.browser.set({})
+
+ def exit_mainloop(self):
+ self.w.parent.debugger_quitting = 1
+
+ #
+
+ def showframe(self, stackindex):
+ (frame, lineno) = self.stack[stackindex]
+ W.SetCursor('watch')
+ filename = frame.f_code.co_filename
+ if filename <> self.file:
+ editor = self.geteditor(filename)
+ if editor:
+ self.w.panes.bottom.src.source.set(editor.get(), filename)
+ else:
+ try:
+ f = open(filename, 'rb')
+ data = f.read()
+ f.close()
+ except IOError:
+ if filename[-3:] == '.py':
+ import imp
+ modname = os.path.basename(filename)[:-3]
+ try:
+ f, filename, (suff, mode, dummy) = imp.find_module(modname)
+ except ImportError:
+ self.w.panes.bottom.src.source.set('canıt find file')
+ else:
+ f.close()
+ if suff == '.py':
+ f = open(filename, 'rb')
+ data = f.read()
+ f.close()
+ self.w.panes.bottom.src.source.set(data, filename)
+ else:
+ self.w.panes.bottom.src.source.set('canıt find file')
+ else:
+ self.w.panes.bottom.src.source.set('canıt find file')
+ else:
+ self.w.panes.bottom.src.source.set(data, filename)
+ self.file = filename
+ self.w.panes.bottom.srctitle.set('Source: ' + filename + ((lineno > 0) and (' (line %d)' % lineno) or ' '))
+ self.goto_line(lineno)
+ self.lineno = lineno
+ self.showvars((frame, lineno))
+
+ def showvars(self, (frame, lineno)):
+ if frame.f_locals is not frame.f_globals:
+ locals = frame.f_locals
+ else:
+ locals = {'Same as Globals':''}
+ filteredlocals = {}
+ for key, value in locals.items():
+ # empty key is magic for Python 1.4; '.' is magic for 1.5...
+ if not key or key[0] <> '.':
+ filteredlocals[key] = value
+ self.w.panes.browserpanes.locals.browser.set(filteredlocals)
+ self.w.panes.browserpanes.globals.browser.set(frame.f_globals)
+
+ def showstack(self, stackindex):
+ stack = []
+ for frame, lineno in self.stack[1:]:
+ filename = frame.f_code.co_filename
+ try:
+ filename = _filenames[filename]
+ except KeyError:
+ if filename[:1] + filename[-1:] <> '<>':
+ filename = os.path.basename(filename)
+ _filenames[frame.f_code.co_filename] = filename
+ funcname = frame.f_code.co_name
+ if funcname == '?':
+ funcname = '<toplevel>'
+ stack.append(filename + ': ' + funcname)
+ if stack <> self.laststack:
+ self.w.panes.browserpanes.stacklist.stack.set(stack)
+ self.laststack = stack
+ sel = [stackindex - 1]
+ self.w.panes.browserpanes.stacklist.stack.setselection(sel)
+ self.laststacksel = sel
+
+ def goto_line(self, lineno):
+ if lineno > 0:
+ self.w.panes.bottom.src.source.selectline(lineno - 1)
+ else:
+ self.w.panes.bottom.src.source.setselection(0, 0)
+
+ # bdb entry points
+
+# def user_call(self, frame, argument_list):
+# self.reason = 'Calling'
+# self.interaction(frame, None)
+
+ def user_line(self, frame):
+ # This function is called when we stop or break at this line
+ self.reason = 'Stopped'
+ self.interaction(frame, None)
+
+ def user_return(self, frame, return_value):
+ # This function is called when a return trap is set here
+ fname = frame.f_code.co_name
+ if fname <> '?':
+ self.reason = 'Returning from %s()' % frame.f_code.co_name
+ frame.f_locals['__return__'] = return_value
+ elif frame.f_back is self.botframe:
+ self.reason = 'Done'
+ else:
+ self.reason = 'Returning'
+ self.interaction(frame, None, 1)
+
+ def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
+ # This function is called when we stop or break at this line
+ self.reason = self.formatexception(exc_type, exc_value)
+ self.interaction(frame, exc_traceback)
+
+ def formatexception(self, exc_type, exc_value):
+ if exc_type == SyntaxError:
+ try:
+ value, (filename, lineno, charno, line) = exc_value
+ except:
+ pass
+ else:
+ return str(exc_type) + ': ' + str(value)
+ if type(exc_type) == types.ClassType:
+ nice = exc_type.__name__
+ else:
+ nice = str(exc_type)
+ value = str(exc_value)
+ if exc_value and value:
+ nice = nice + ": " + value
+ return nice
+
+ def forget(self):
+ self.stack = []
+ self.curindex = 0
+ self.curframe = None
+
+ def setup(self, f, t, isreturning = 0):
+ self.forget()
+ self.stack, self.curindex = self.get_stack(f, t)
+ self.curframe = self.stack[self.curindex - isreturning][0]
+
+ def interaction(self, frame, traceback, isreturning = 0):
+ saveport = Qd.GetPort()
+ self.w.select()
+ try:
+ self.setup(frame, traceback, isreturning)
+ self.setstate('stopped')
+ stackindex = self.curindex
+ if isreturning:
+ if frame.f_back is not self.botframe:
+ stackindex = stackindex - 1
+ self.showstack(stackindex)
+ self.showframe(stackindex)
+ self.w.parent.debugger_mainloop()
+ self.forget()
+ finally:
+ Qd.SetPort(saveport)
+
+ # bdb customization
+
+ def trace_dispatch(self, frame, event, arg, TickCount = Evt.TickCount):
+ if TickCount() - self.tracingmonitortime > 15:
+ self.tracingmonitortime = TickCount()
+ self.w.panes.bottom.tracingmonitor.toggle()
+ try:
+ try:
+ MacOS.EnableAppswitch(0)
+ if self.quitting:
+ # returning None is not enough, a former BdbQuit exception
+ # might have been eaten by the print statement
+ raise bdb.BdbQuit
+ if event == 'line':
+ return self.dispatch_line(frame)
+ if event == 'call':
+ return self.dispatch_call(frame, arg)
+ if event == 'return':
+ return self.dispatch_return(frame, arg)
+ if event == 'exception':
+ return self.dispatch_exception(frame, arg)
+ print 'bdb.Bdb.dispatch: unknown debugging event:', `event`
+ return self.trace_dispatch
+ finally:
+ MacOS.EnableAppswitch(-1)
+ except KeyboardInterrupt:
+ self.set_step()
+ return self.trace_dispatch
+ except bdb.BdbQuit:
+ if self.continuewithoutdebugger:
+ self.clear_tracefuncs()
+ return
+ else:
+ raise bdb.BdbQuit
+ except:
+ print 'XXX Exception during debugger interaction.', \
+ self.formatexception(sys.exc_type, sys.exc_value)
+ return self.trace_dispatch
+
+ def dispatch_call(self, frame, arg):
+ if not self.tracemagic and \
+ frame.f_code.co_name[:2] == '__' == frame.f_code.co_name[-2:] and \
+ frame.f_code.co_name <> '__init__':
+ return
+ if self.botframe is None:
+ # First call of dispatch since reset()
+ self.botframe = frame.f_back # xxx !!! added f_back
+ return self.trace_dispatch
+ if not (self.stop_here(frame) or self.break_anywhere(frame)):
+ # No need to trace this function
+ return # None
+ self.user_call(frame, arg)
+ if self.quitting:
+ raise bdb.BdbQuit
+ return self.trace_dispatch
+
+ def set_continue(self):
+ # Don't stop except at breakpoints or when finished
+ self.stopframe = self.botframe
+ self.returnframe = None
+ self.quitting = 0
+ # unlike in bdb/pdb, there's a chance that breakpoints change
+ # *while* a program (this program ;-) is running. It's actually quite likely.
+ # So we don't delete frame.f_trace until the bottom frame if there are no breakpoints.
+
+ def set_break(self, filename, lineno):
+ if not self.breaks.has_key(filename):
+ self.breaks[filename] = []
+ list = self.breaks[filename]
+ if lineno in list:
+ return 'There is already a breakpoint there!'
+ list.append(lineno)
+ list.sort() # I want to keep them neatly sorted; easier for drawing
+ self.update_breaks(filename)
+
+ def clear_break(self, filename, lineno):
+ bdb.Bdb.clear_break(self, filename, lineno)
+ self.update_breaks(filename)
+
+ def clear_all_file_breaks(self, filename):
+ bdb.Bdb.clear_all_file_breaks(self, filename)
+ self.update_breaks(filename)
+
+ def clear_all_breaks(self):
+ bdb.Bdb.clear_all_breaks(self)
+ for editors in self.editors.values():
+ for editor in editors:
+ editor.drawbreakpoints()
+
+ # special
+
+ def toggle_break(self, filename, lineno):
+ if self.get_break(filename, lineno):
+ self.clear_break(filename, lineno)
+ else:
+ self.set_break(filename, lineno)
+
+ def clear_breaks_above(self, filename, above):
+ if not self.breaks.has_key(filename):
+ return 'There are no breakpoints in that file!'
+ for lineno in self.breaks[filename][:]:
+ if lineno > above:
+ self.breaks[filename].remove(lineno)
+ if not self.breaks[filename]:
+ del self.breaks[filename]
+
+ # editor stuff
+
+ def update_breaks(self, filename):
+ if self.breaksviewer:
+ self.breaksviewer.update()
+ if self.editors.has_key(filename):
+ for editor in self.editors[filename]:
+ if editor._debugger: # XXX
+ editor.drawbreakpoints()
+ else:
+ print 'xxx dead editor!'
+
+ def update_allbreaks(self):
+ if self.breaksviewer:
+ self.breaksviewer.update()
+ for filename in self.breaks.keys():
+ if self.editors.has_key(filename):
+ for editor in self.editors[filename]:
+ if editor._debugger: # XXX
+ editor.drawbreakpoints()
+ else:
+ print 'xxx dead editor!'
+
+ def register_editor(self, editor, filename):
+ if not filename:
+ return
+ if not self.editors.has_key(filename):
+ self.editors[filename] = [editor]
+ elif editor not in self.editors[filename]:
+ self.editors[filename].append(editor)
+
+ def unregister_editor(self, editor, filename):
+ if not filename:
+ return
+ try:
+ self.editors[filename].remove(editor)
+ if not self.editors[filename]:
+ del self.editors[filename]
+ # if this was an untitled window, clear the breaks.
+ if filename[:1] == '<' and filename[-1:] == '>' and \
+ self.breaks.has_key(filename):
+ self.clear_all_file_breaks(filename)
+ except (KeyError, ValueError):
+ pass
+
+
+class SourceViewer(W.PyEditor):
+
+ def __init__(self, *args, **kwargs):
+ apply(W.PyEditor.__init__, (self,) + args, kwargs)
+ self.bind('<click>', self.clickintercept)
+
+ def clickintercept(self, point, modifiers):
+ if self._parentwindow._currentwidget <> self and not self.pt_in_breaks(point):
+ self._parentwindow.xxx___select(self)
+ return 1
+
+ def _getviewrect(self):
+ l, t, r, b = self._bounds
+ if self._debugger:
+ return (l + 12, t + 2, r - 1, b - 2)
+ else:
+ return (l + 5, t + 2, r - 1, b - 2)
+
+ def select(self, onoff, isclick = 0):
+ if W.SelectableWidget.select(self, onoff):
+ return
+ self.SetPort()
+ #if onoff:
+ # self.ted.WEActivate()
+ #else:
+ # self.ted.WEDeactivate()
+ self.drawselframe(onoff)
+
+ def drawselframe(self, onoff):
+ pass
+
+
+class BreakpointsViewer:
+
+ def __init__(self, debugger):
+ self.debugger = debugger
+ import Lists
+ self.w = W.Window((300, 250), 'Breakpoints', minsize = (200, 200))
+ self.w.panes = W.HorizontalPanes((8, 8, -8, -32), (0.3, 0.7))
+ self.w.panes.files = W.List(None, callback = self.filehit) #, flags = Lists.lOnlyOne)
+ self.w.panes.gr = W.Group(None)
+ self.w.panes.gr.breaks = W.List((0, 0, -130, 0), callback = self.linehit) #, flags = Lists.lOnlyOne)
+ self.w.panes.gr.openbutton = W.Button((-80, 4, 0, 16), 'ViewŠ', self.openbuttonhit)
+ self.w.panes.gr.deletebutton = W.Button((-80, 28, 0, 16), 'Delete', self.deletebuttonhit)
+
+ self.w.bind('<close>', self.close)
+ self.w.bind('backspace', self.w.panes.gr.deletebutton.push)
+
+ self.setup()
+ self.w.open()
+ self.w.panes.gr.openbutton.enable(0)
+ self.w.panes.gr.deletebutton.enable(0)
+ self.curfile = None
+
+ def deletebuttonhit(self):
+ if self.w._currentwidget == self.w.panes.files:
+ self.del_filename()
+ else:
+ self.del_number()
+ self.checkbuttons()
+
+ def del_number(self):
+ if self.curfile is None:
+ return
+ sel = self.w.panes.gr.breaks.getselectedobjects()
+ for lineno in sel:
+ self.debugger.clear_break(self.curfile, lineno)
+
+ def del_filename(self):
+ sel = self.w.panes.files.getselectedobjects()
+ for filename in sel:
+ self.debugger.clear_all_file_breaks(filename)
+ self.debugger.update_allbreaks()
+
+ def setup(self):
+ files = self.debugger.breaks.keys()
+ files.sort()
+ self.w.panes.files.set(files)
+
+ def close(self):
+ self.debugger.breaksviewer = None
+ self.debugger = None
+
+ def update(self):
+ sel = self.w.panes.files.getselectedobjects()
+ self.setup()
+ self.w.panes.files.setselectedobjects(sel)
+ sel = self.w.panes.files.getselection()
+ if len(sel) == 0 and self.curfile:
+ self.w.panes.files.setselectedobjects([self.curfile])
+ self.filehit(0)
+
+ def select(self):
+ self.w.select()
+
+ def selectfile(self, file):
+ self.w.panes.files.setselectedobjects([file])
+ self.filehit(0)
+
+ def openbuttonhit(self):
+ self.filehit(1)
+
+ def filehit(self, isdbl):
+ sel = self.w.panes.files.getselectedobjects()
+ if isdbl:
+ for filename in sel:
+ lineno = None
+ if filename == self.curfile:
+ linesel = self.w.panes.gr.breaks.getselectedobjects()
+ if linesel:
+ lineno = linesel[-1]
+ elif self.w.panes.gr.breaks:
+ lineno = self.w.panes.gr.breaks[0]
+ editor = self.w._parentwindow.parent.openscript(filename, lineno)
+ editor.showbreakpoints(1)
+ return
+ if len(sel) == 1:
+ file = sel[0]
+ filebreaks = self.debugger.breaks[file][:]
+ if self.curfile == file:
+ linesel = self.w.panes.gr.breaks.getselectedobjects()
+ self.w.panes.gr.breaks.set(filebreaks)
+ if self.curfile == file:
+ self.w.panes.gr.breaks.setselectedobjects(linesel)
+ self.curfile = file
+ else:
+ if len(sel) <> 0:
+ self.curfile = None
+ self.w.panes.gr.breaks.set([])
+ self.checkbuttons()
+
+ def linehit(self, isdbl):
+ if isdbl:
+ files = self.w.panes.files.getselectedobjects()
+ if len(files) <> 1:
+ return
+ filename = files[0]
+ linenos = self.w.panes.gr.breaks.getselectedobjects()
+ if not linenos:
+ return
+ lineno = linenos[-1]
+ editor = self.w._parentwindow.parent.openscript(filename, lineno)
+ editor.showbreakpoints(1)
+ self.checkbuttons()
+
+ def checkbuttons(self):
+ if self.w.panes.files.getselection():
+ self.w.panes.gr.openbutton.enable(1)
+ self.w._parentwindow.setdefaultbutton(self.w.panes.gr.openbutton)
+ if self.w._currentwidget == self.w.panes.files:
+ if self.w.panes.files.getselection():
+ self.w.panes.gr.deletebutton.enable(1)
+ else:
+ self.w.panes.gr.deletebutton.enable(0)
+ else:
+ if self.w.panes.gr.breaks.getselection():
+ self.w.panes.gr.deletebutton.enable(1)
+ else:
+ self.w.panes.gr.deletebutton.enable(0)
+ else:
+ self.w.panes.gr.openbutton.enable(0)
+ self.w.panes.gr.deletebutton.enable(0)
+
+
+class TracingMonitor(W.Widget):
+
+ def __init__(self, *args, **kwargs):
+ apply(W.Widget.__init__, (self,) + args, kwargs)
+ self.state = 0
+
+ def toggle(self):
+ if hasattr(self, "_parentwindow") and self._parentwindow is not None:
+ self.state = self.state % 2 + 1
+ port = Qd.GetPort()
+ self.SetPort()
+ self.draw()
+ Qd.SetPort(port)
+
+ def reset(self):
+ if self._parentwindow:
+ self.state = 0
+ port = Qd.GetPort()
+ self.SetPort()
+ self.draw()
+ Qd.SetPort(port)
+
+ def draw(self, visRgn = None):
+ if self.state == 2:
+ Qd.PaintOval(self._bounds)
+ else:
+ Qd.EraseOval(self._bounds)
+
+
+# convenience funcs
+
+def postmortem(exc_type, exc_value, tb):
+ d = getdebugger()
+ d.postmortem(exc_type, exc_value, tb)
+
+def start(bottomframe = None):
+ d = getdebugger()
+ d.start(bottomframe)
+
+def startfromhere():
+ d = getdebugger()
+ try:
+ raise 'spam'
+ except:
+ frame = sys.exc_traceback.tb_frame.f_back
+ d.start(frame)
+
+def startfrombottom():
+ d = getdebugger()
+ d.start(_getbottomframe(), 1)
+
+def stop():
+ d = getdebugger()
+ d.stop()
+
+def cont():
+ sys.settrace(None)
+ d = getdebugger()
+ d.set_continue_without_debugger()
+
+def _getbottomframe():
+ try:
+ raise 'spam'
+ except:
+ pass
+ frame = sys.exc_traceback.tb_frame
+ while 1:
+ if frame.f_code.co_name == 'mainloop' or frame.f_back is None:
+ break
+ frame = frame.f_back
+ return frame
+
+_debugger = None
+
+def getdebugger():
+ global _debugger
+ if _debugger is None:
+ _debugger = Debugger()
+ return _debugger