# -*- coding: utf-8 -*- # # Copyright © 2012 Jed Ludlow # based loosley on pylintgui.py by Pierre Raybaut # Licensed under the terms of the MIT License # (see spyderlib/__init__.py for details) """Breakpoint widget""" # pylint: disable=C0103 # pylint: disable=R0903 # pylint: disable=R0911 # pylint: disable=R0201 from spyderlib.qt.QtGui import (QWidget, QTableView, QItemDelegate, QVBoxLayout, QMenu) from spyderlib.qt.QtCore import (Qt, SIGNAL, QTextCodec, QModelIndex, QAbstractTableModel) locale_codec = QTextCodec.codecForLocale() from spyderlib.qt.compat import to_qvariant import sys import os.path as osp # Local imports from spyderlib.baseconfig import get_translation from spyderlib.config import CONF from spyderlib.utils.qthelpers import create_action, add_actions _ = get_translation("p_breakpoints", dirname="spyderplugins") class BreakpointTableModel(QAbstractTableModel): """ Table model for breakpoints dictionary """ def __init__(self, parent, data): QAbstractTableModel.__init__(self, parent) if data is None: data = {} self._data = None self.breakpoints = None self.set_data(data) def set_data(self, data): """Set model data""" self._data = data keys = list(data.keys()) self.breakpoints = [] for key in keys: bp_list = data[key] if bp_list: for item in data[key]: self.breakpoints.append((key, item[0], item[1], "")) self.reset() def rowCount(self, qindex=QModelIndex()): """Array row number""" return len(self.breakpoints) def columnCount(self, qindex=QModelIndex()): """Array column count""" return 4 def sort(self, column, order=Qt.DescendingOrder): """Overriding sort method""" if column == 0: self.breakpoints.sort( key=lambda breakpoint: breakpoint[1]) self.breakpoints.sort( key=lambda breakpoint: osp.basename(breakpoint[0])) elif column == 1: pass elif column == 2: pass elif column == 3: pass self.reset() def headerData(self, section, orientation, role=Qt.DisplayRole): """Overriding method headerData""" if role != Qt.DisplayRole: return to_qvariant() i_column = int(section) if orientation == Qt.Horizontal: headers = (_("File"), _("Line"), _("Condition"), "") return to_qvariant( headers[i_column] ) else: return to_qvariant() def get_value(self, index): """Return current value""" return self.breakpoints[index.row()][index.column()] def data(self, index, role=Qt.DisplayRole): """Return data at table index""" if not index.isValid(): return to_qvariant() if role == Qt.DisplayRole: if index.column() == 0: value = osp.basename(self.get_value(index)) return to_qvariant(value) else: value = self.get_value(index) return to_qvariant(value) elif role == Qt.TextAlignmentRole: return to_qvariant(int(Qt.AlignLeft|Qt.AlignVCenter)) elif role == Qt.ToolTipRole: if index.column() == 0: value = self.get_value(index) return to_qvariant(value) else: return to_qvariant() class BreakpointDelegate(QItemDelegate): def __init__(self, parent=None): QItemDelegate.__init__(self, parent) class BreakpointTableView(QTableView): def __init__(self, parent, data): QTableView.__init__(self, parent) self.model = BreakpointTableModel(self, data) self.setModel(self.model) self.delegate = BreakpointDelegate(self) self.setItemDelegate(self.delegate) self.setup_table() def setup_table(self): """Setup table""" self.horizontalHeader().setStretchLastSection(True) self.adjust_columns() self.columnAt(0) # Sorting columns self.setSortingEnabled(False) self.sortByColumn(0, Qt.DescendingOrder) def adjust_columns(self): """Resize three first columns to contents""" for col in range(3): self.resizeColumnToContents(col) def mouseDoubleClickEvent(self, event): """Reimplement Qt method""" index_clicked = self.indexAt(event.pos()) if self.model.breakpoints: filename = self.model.breakpoints[index_clicked.row()][0] line_number_str = self.model.breakpoints[index_clicked.row()][1] self.emit(SIGNAL("edit_goto(QString,int,QString)"), filename, int(line_number_str), '') if index_clicked.column()==2: self.emit(SIGNAL("set_or_edit_conditional_breakpoint()")) def contextMenuEvent(self, event): index_clicked = self.indexAt(event.pos()) actions = [] self.popup_menu = QMenu(self) clear_all_breakpoints_action = create_action(self, _("Clear breakpoints in all files"), triggered=lambda: self.emit(SIGNAL('clear_all_breakpoints()'))) actions.append(clear_all_breakpoints_action) if self.model.breakpoints: filename = self.model.breakpoints[index_clicked.row()][0] lineno = int(self.model.breakpoints[index_clicked.row()][1]) clear_breakpoint_action = create_action(self, _("Clear this breakpoint"), triggered=lambda filename=filename, lineno=lineno: \ self.emit(SIGNAL('clear_breakpoint(QString,int)'), filename, lineno)) actions.insert(0,clear_breakpoint_action) edit_breakpoint_action = create_action(self, _("Edit this breakpoint"), triggered=lambda filename=filename, lineno=lineno: \ (self.emit(SIGNAL('edit_goto(QString,int,QString)'), filename, lineno, ''), self.emit(SIGNAL("set_or_edit_conditional_breakpoint()"))) ) actions.append(edit_breakpoint_action) add_actions(self.popup_menu, actions) self.popup_menu.popup(event.globalPos()) event.accept() class BreakpointWidget(QWidget): """ Breakpoint widget """ VERSION = '1.0.0' def __init__(self, parent): QWidget.__init__(self, parent) self.setWindowTitle("Breakpoints") self.dictwidget = BreakpointTableView(self, self._load_all_breakpoints()) layout = QVBoxLayout() layout.addWidget(self.dictwidget) self.setLayout(layout) self.connect(self.dictwidget, SIGNAL('clear_all_breakpoints()'), lambda: self.emit(SIGNAL('clear_all_breakpoints()'))) self.connect(self.dictwidget, SIGNAL('clear_breakpoint(QString,int)'), lambda s1, lino: self.emit( SIGNAL('clear_breakpoint(QString,int)'), s1, lino)) self.connect(self.dictwidget, SIGNAL("edit_goto(QString,int,QString)"), lambda s1, lino, s2: self.emit( SIGNAL("edit_goto(QString,int,QString)"), s1, lino, s2)) self.connect(self.dictwidget, SIGNAL('set_or_edit_conditional_breakpoint()'), lambda: self.emit(SIGNAL('set_or_edit_conditional_breakpoint()'))) def _load_all_breakpoints(self): bp_dict = CONF.get('run', 'breakpoints', {}) for filename in list(bp_dict.keys()): if not osp.isfile(filename): bp_dict.pop(filename) return bp_dict def get_data(self): pass def set_data(self): bp_dict = self._load_all_breakpoints() self.dictwidget.model.set_data(bp_dict) self.dictwidget.adjust_columns() self.dictwidget.sortByColumn(0, Qt.DescendingOrder) def test(): """Run breakpoint widget test""" from spyderlib.utils.qthelpers import qapplication app = qapplication() widget = BreakpointWidget(None) widget.show() sys.exit(app.exec_()) if __name__ == '__main__': test()