import sys import javax.swing as swing import javax.swing.table.AbstractTableModel as AbstractTableModel import java.awt as awt import java.lang.Object as Object import JESDebugger import java.util.Hashtable as Hashtable import JESGutter MAX_LINES = 200 CROPPED_MESSAGE = '<>' BUTTON_SIZE=(50,50) HIGHLIGHT_COLOR = awt.Color.green DEFAULT_MAX_REFRESH_RATE = 5.0 # per second DEFAULT_RATE_AT_RUNNING_MODE = 0.3 def buttonFont(b): return '' + b + '' def variableDialog(ui): var = swing.JOptionPane.showInputDialog(ui, 'Please type the variable to watch') return var def pickVariable(ui, vars): if len(vars) > 0: var = swing.JOptionPane.showInputDialog(ui, "Choose Variable to remove", "Input", swing.JOptionPane.INFORMATION_MESSAGE, None, vars, vars[0]) return var else: swing.JOptionPane.showMessageDialog(ui, 'There are no variables to remove', 'Error', swing.JOptionPane.ERROR_MESSAGE) return None class DBControlPanel(swing.JPanel): def __init__(self, debugger): self.lastValue = None self.debugger = debugger MAX_SPEED = debugger.MAX_SPEED # slider needs labeling self.slider = swing.JSlider(swing.JSlider.HORIZONTAL, 0, MAX_SPEED, self.debugger.speed, stateChanged=self.stateChanged) self.last_speed = self.debugger.speed labels = Hashtable() labels.put(0, swing.JLabel('slow')) labels.put(MAX_SPEED, swing.JLabel('fast')) self.slider.labelTable = labels self.slider.paintLabels = 1 self.addButton = swing.JButton(swing.ImageIcon('plus.jpg'), actionPerformed=self.actionPerformed, toolTipText='add Variable', preferredSize=BUTTON_SIZE) self.deleteButton = swing.JButton(swing.ImageIcon('minus.jpg'), actionPerformed=self.actionPerformed, toolTipText='remove Variable', preferredSize=BUTTON_SIZE) self.stepButton = swing.JButton(swing.ImageIcon('boot.jpg'), actionPerformed=self.actionPerformed, toolTipText='step', preferredSize=BUTTON_SIZE) # pic of a boot would be nice self.pauseIcon = swing.ImageIcon('pause.jpg') self.runIcon = swing.ImageIcon('run.jpg') self.runButton = swing.JButton(self.runIcon, actionPerformed=self.actionPerformed, toolTipText='run', preferredSize=BUTTON_SIZE) self.fullspeedButton = swing.JButton(swing.ImageIcon('fullspeed.jpg'), actionPerformed=self.actionPerformed, toolTipText='full speed', preferredSize=BUTTON_SIZE) self.stopButton = swing.JButton(swing.ImageIcon('stop.jpg'), actionPerformed=self.actionPerformed, toolTipText='stop', preferredSize=BUTTON_SIZE) self.stepButton.enabled = 0 self.fullspeedButton.enabled = 0 self.setLayout(swing.BoxLayout(self, swing.BoxLayout.X_AXIS)) self.add(self.slider) self.add(self.addButton) self.add(self.deleteButton) self.add(self.stepButton) self.add(self.runButton) self.add(self.fullspeedButton) self.add(self.stopButton) self.stop() def stateChanged(self, e): value = self.slider.getValue() self.debugger.speed = value if value == 0: self.stepButton.setEnabled(1) self.pauseState() elif self.lastValue == 0: self.stepButton.setEnabled(0) self.run() self.lastValue = value def actionPerformed(self, e): source = e.getSource() if source == self.stepButton: self.debugger.step() elif source == self.runButton: if source.icon == self.runIcon: self.run() else: self.pause() elif source == self.fullspeedButton: self.fullspeed() elif source == self.stopButton: self.debugger.stopThread() self.stop() elif source == self.addButton: self.debugger.watcher.watchVariable() elif source == self.deleteButton: self.debugger.watcher.unwatchVariable() def refreshSlider(self): self.slider.value = self.debugger.speed def run(self): self.runButton.icon = self.pauseIcon self.runButton.toolTipText = 'pause' if self.debugger.speed == 0: self.debugger.setSpeed(self.last_speed) self.runButton.enabled = 1 self.fullspeedButton.enabled = 1 self.stepButton.enabled = 0 self.stopButton.enabled = 1 self.addButton.enabled = 0 self.deleteButton.enabled = 0 self.debugger.step() def fullspeed(self): # kinda like run, but full speed self.runButton.icon = self.pauseIcon self.runButton.toolTipText = 'pause' self.debugger.setSpeed(self.debugger.MAX_SPEED) self.fullspeedButton.enabled = 0 self.runButton.enabled = 1 self.stepButton.enabled = 0 self.stopButton.enabled = 1 self.addButton.enabled = 0 self.deleteButton.enabled = 0 self.debugger.step() def stop(self): self.stepButton.enabled = 0 self.runButton.enabled = 0 self.stopButton.enabled = 0 self.addButton.enabled = 1 self.deleteButton.enabled = 1 self.fullspeedButton.enabled = 0 def pause(self): self.last_speed = self.debugger.speed self.debugger.setSpeed(0) self.pauseState() def pauseState(self): self.runButton.icon = self.runIcon self.runButton.toolTipText = 'run' self.stepButton.enabled = 1 self.runButton.enabled = 1 self.fullspeedButton.enabled = 1 self.addButton.enabled = 1 self.deleteButton.enabled = 1 self.stopButton.enabled = 1 class ExecHistory(AbstractTableModel): def __init__(self, debugger): self.debugger = debugger self.variables = [] self.lines = [] self.nextLine = None self.max_refresh_rate = debugger.MAX_SPEED self.rate_at_running_mode = DEFAULT_RATE_AT_RUNNING_MODE def fireChanged(self): self.fireTableStructureChanged() def getColumnName(self, col): if col == 0: return 'step' elif col == 1: return 'line' elif col == 2: return 'instruction' else: return 'var:' + self.variables[col - 3] def setVariables(self, vars): self.variables = vars # need to signal the table view here self.fireTableStructureChanged() def appendVariable(self, var): self.variables.append(var) self.fireTableStructureChanged() def removeVariable(self, var): self.variables.remove(var) self.fireTableStructureChanged() def clearVariables(self): self.variables = [] self.fireTableStructureChanged() def addLine(self, line_no, instr, values): #calculate whether to fire or not import random real_speed = (float(self.debugger.speed) / self.debugger.speed_factor) if self.debugger.speed == 0: fire = 1 else: inter_rate = self.rate_at_running_mode / real_speed #print "inter_rate", inter_rate fire = (self.max_refresh_rate / real_speed > 1) or (random.uniform(0, 1) < inter_rate) #fire = 0 if self.nextLine: if len(self.lines) > MAX_LINES: if self.lines[0][1] == CROPPED_MESSAGE: self.lines.remove(self.lines[1]) if fire: self.fireTableRowsDeleted(1, 1) else: line = ['-', CROPPED_MESSAGE] self.lines[0] = line if fire: self.fireTableRowsUpdated(0, 0) self.nextLine.extend(values) if fire: self.fireTableRowsUpdated(len(self.lines)-1, len(self.lines)-1) self.nextLine = [] if len(self.lines) > 0: self.nextLine.append(self.lines[len(self.lines)-1][0]+1) else: self.nextLine.append(1) self.nextLine.append(line_no) self.nextLine.append(instr) self.lines.append(self.nextLine) if fire: self.fireTableRowsInserted(len(self.lines)-1, len(self.lines)-1) self.debugger.interpreter.program.gui.editor.document.highlightLine(self.nextLine[1]) def endExecution(self): if self.nextLine: # also update the editor currentline highlight #self.debugger.interpreter.program.gui.gutter.removeLineMark() self.debugger.interpreter.program.gui.editor.document.removeLineHighlighting() self.nextLine = None def clear(self): self.nextLine = None numrows = len(self.lines) self.lines = [] if numrows > 0: self.fireTableRowsDeleted(0, numrows-1) def snapShot(self, line_no, instr): values = [] for var in self.variables: try: value = eval(var, self.debugger.curframe.f_globals, self.debugger.curframe.f_locals) values.append(value) except: values.append('-') # add dummy #t, v = sys.exc_info()[:2] #if type(t) == type(''): #exc_type_name = t #else: exc_type_name = t.__name__ #print '***', exc_type_name + ':', `v` self.addLine(line_no, instr, values) # TableModel required methods def getColumnCount(self): ret = 3 + len(self.variables) return ret def getRowCount(self): return len(self.lines) def getValueAt(self, row, col): line = self.lines[row] if col < len(line): return self.lines[row][col] else: return '' def setColumnWidths(self, table): columnModel = table.columnModel columnModel.getColumn(0).preferredWidth = 10 columnModel.getColumn(1).preferredWidth = 10 # line number columnModel.getColumn(2).preferredWidth = 150 # instruction for i in range(len(self.variables)): columnModel.getColumn(i + 3).setPreferredWidth(15) class MyTable(swing.JTable): def tableChanged(self, event): swing.JTable.tableChanged(self, event) if event.getFirstRow() == swing.event.TableModelEvent.HEADER_ROW: self.model.setColumnWidths(self) class MyRenderer(swing.JLabel, swing.table.TableCellRenderer): def __init__(self): self.opaque = 1 def getTableCellRendererComponent(self, table, value, isSelected, hasFocus, row, col): self.text = str(value) if row <> table.rowCount - 1: self.background = awt.Color.white else: self.background = HIGHLIGHT_COLOR return self class JESDBVariableWatcher(swing.JFrame): def __init__(self, debugger, controlPanel): swing.JFrame.__init__(self, title='JES Debugger') # variables correspond to columns on the right self.debugger = debugger self.history = ExecHistory(debugger) table = MyTable(self.history) table.preferredScrollableViewportSize = (300,400) self.rendererComponent = swing.JLabel(opaque = 1) table.setDefaultRenderer(Object, MyRenderer()) self.history.setColumnWidths(table) scrollPane = swing.JScrollPane(table) scrollPane.verticalScrollBar.model.stateChanged = self.stateChanged self.contentPane.setLayout(awt.BorderLayout()) self.contentPane.add(scrollPane, awt.BorderLayout.CENTER) self.contentPane.add(controlPanel, awt.BorderLayout.NORTH) self.lastScrollMaximum = None self.windowClosing = self.windowClosingg # lol! self.pack() def endExecution(self): self.history.endExecution() def stateChanged(self, event): brmodel = event.source if brmodel.maximum <> self.lastScrollMaximum: brmodel.value = brmodel.maximum self.lastScrollMaximum = brmodel.maximum def watchVariable(self): var = variableDialog(self) if var: self.addVariable(var) def unwatchVariable(self): var = pickVariable(self, self.debugger.watcher.getVariables()) if var: self.removeVariable(var) def windowClosingg(self, event): self.debugger.interpreter.toggle_debug_mode(0) self.debugger.stopThread() def snapShot(self, line_no, instr): self.history.snapShot(line_no, instr) def setVariables(self, vars): self.history.setVariables(vars) def addVariable(self, var): self.appendVariable(var) def removeVariable(self, var): self.history.removeVariable(var) def appendVariable(self, var): self.history.appendVariable(var) def clearVariables(self): self.history.clearVariables() def getVariables(self): return self.history.variables def clear(self): self.history.clear()