diff -r 21df384d6150 -r cc920e534ac0 eric6/Debugger/DebugViewer.py --- a/eric6/Debugger/DebugViewer.py Wed Jan 29 19:38:13 2020 +0100 +++ b/eric6/Debugger/DebugViewer.py Thu Jan 30 19:37:03 2020 +0100 @@ -23,7 +23,7 @@ import os -from PyQt5.QtCore import pyqtSignal +from PyQt5.QtCore import pyqtSignal, Qt from PyQt5.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QSizePolicy, QPushButton, QComboBox, QLabel, QTreeWidget, QTreeWidgetItem, QHeaderView, QFrame @@ -69,7 +69,7 @@ self.setLayout(self.__mainLayout) # add the viewer showing the connected debug backends - self.__debuggersLayout = QHBoxLayout(self) + self.__debuggersLayout = QHBoxLayout() self.__debuggersLayout.addWidget(QLabel(self.tr("Debuggers:"))) self.__debuggersCombo = QComboBox(self) self.__debuggersCombo.setSizePolicy( @@ -77,7 +77,7 @@ self.__debuggersLayout.addWidget(self.__debuggersCombo) self.__mainLayout.addLayout(self.__debuggersLayout) - self.__debuggersCombo.currentTextChanged.connect( + self.__debuggersCombo.currentIndexChanged[str].connect( self.__debuggerSelected) # add a line to separate debugger selector from debugger specific parts @@ -264,11 +264,29 @@ self.currentStack = None self.framenr = 0 - self.debugServer.clientStack.connect(self.handleClientStack) - self.__autoViewSource = Preferences.getDebugger("AutoViewSourceCode") self.sourceButton.setVisible(not self.__autoViewSource) + # connect somer debug server signals + self.debugServer.clientStack.connect( + self.handleClientStack) + self.debugServer.clientThreadList.connect( + self.showThreadList) + self.debugServer.clientDebuggerIds.connect( + self.showDebuggersList) + self.debugServer.passiveDebugStarted.connect( + self.handleDebuggingStarted) + self.debugServer.clientLine.connect( + self.__clientLine) + + self.debugServer.clientException.connect( + self.exceptionLogger.addException) + self.debugServer.passiveDebugStarted.connect( + self.exceptionLogger.debuggingStarted) + + self.debugServer.clientLine.connect( + self.breakpointViewer.highlightBreakpoint) + def handlePreferencesChanged(self): """ Public slot to handle the preferencesChanged signal. @@ -283,9 +301,15 @@ @param debugUI reference to the DebugUI object (DebugUI) """ self.debugUI = debugUI - self.debugUI.clientStack.connect(self.handleClientStack) self.callStackViewer.setDebugger(debugUI) + # connect some debugUI signals + self.debugUI.clientStack.connect(self.handleClientStack) + self.debugUI.debuggingStarted.connect( + self.exceptionLogger.debuggingStarted) + self.debugUI.debuggingStarted.connect( + self.handleDebuggingStarted) + def handleResetUI(self): """ Public method to reset the SBVviewer. @@ -371,24 +395,45 @@ else: self.__tabWidget.setCurrentWidget(self.lvWidget) - def handleClientStack(self, stack): + def handleClientStack(self, stack, debuggerId): """ Public slot to show the call stack of the program being debugged. @param stack list of tuples with call stack data (file name, line number, function name, formatted argument/values list) + @type list of tuples of (str, str, str, str) + @param debuggerId ID of the debugger backend + @type str """ - block = self.stackComboBox.blockSignals(True) - self.framenr = 0 - self.stackComboBox.clear() - self.currentStack = stack - self.sourceButton.setEnabled(len(stack) > 0) - for s in stack: - # just show base filename to make it readable - s = (os.path.basename(s[0]), s[1], s[2]) - self.stackComboBox.addItem('{0}:{1}:{2}'.format(*s)) - self.stackComboBox.blockSignals(block) + if debuggerId == self.__debuggersCombo.currentText(): + block = self.stackComboBox.blockSignals(True) + self.framenr = 0 + self.stackComboBox.clear() + self.currentStack = stack + self.sourceButton.setEnabled(len(stack) > 0) + for s in stack: + # just show base filename to make it readable + s = (os.path.basename(s[0]), s[1], s[2]) + self.stackComboBox.addItem('{0}:{1}:{2}'.format(*s)) + self.stackComboBox.blockSignals(block) + + def __clientLine(self, fn, line, debuggerId): + """ + Private method to handle a change to the current line. + @param fn filename + @type str + @param line linenumber + @type int + @param debuggerId ID of the debugger backend + @type str + """ + if debuggerId: + index = self.__debuggersCombo.findText(debuggerId, Qt.MatchExactly) + if index >= 0: + self.__debuggersCombo.setItemIcon( + index, UI.PixmapCache.getIcon("exceptions.png")) + def setVariablesFilter(self, globalsFilter, localsFilter): """ Public slot to set the local variables filter. @@ -471,41 +516,68 @@ """ self.__tabWidget.setCurrentWidget(widget) - def showThreadList(self, currentID, threadList): + def showThreadList(self, currentID, threadList, debuggerId): """ Public method to show the thread list. - @param currentID id of the current thread (integer) + @param currentID id of the current thread + @type int @param threadList list of dictionaries containing the thread data + @type list of dict + @param debuggerId ID of the debugger backend + @type str """ - citm = None + debugStatus = -1 # i.e. running - self.__threadList.clear() - for thread in threadList: - if thread.get('except', False): - state = self.tr("waiting at exception") - icon = "exceptions.png" - elif thread['broken']: - state = self.tr("waiting at breakpoint") - icon = "mediaPlaybackPause.png" - else: - state = self.tr("running") - icon = "mediaPlaybackStart.png" - itm = QTreeWidgetItem(self.__threadList, - ["{0:d}".format(thread['id']), - thread['name'], state]) - itm.setIcon(0, UI.PixmapCache.getIcon(icon)) - if thread['id'] == currentID: - citm = itm + if debuggerId == self.__debuggersCombo.currentText(): + citm = None + + self.__threadList.clear() + for thread in threadList: + if thread.get('except', False): + state = self.tr("waiting at exception") + icon = "exceptions.png" + debugStatus = 1 + elif thread['broken']: + state = self.tr("waiting at breakpoint") + icon = "mediaPlaybackPause.png" + if debugStatus < 1: + debugStatus = 0 + else: + state = self.tr("running") + icon = "mediaPlaybackStart.png" + itm = QTreeWidgetItem(self.__threadList, + ["{0:d}".format(thread['id']), + thread['name'], state]) + itm.setIcon(0, UI.PixmapCache.getIcon(icon)) + if thread['id'] == currentID: + citm = itm + + self.__threadList.header().resizeSections( + QHeaderView.ResizeToContents) + self.__threadList.header().setStretchLastSection(True) + + if citm: + self.__doThreadListUpdate = False + self.__threadList.setCurrentItem(citm) + self.__doThreadListUpdate = True + else: + for thread in threadList: + if thread.get('except', False): + debugStatus = 1 + elif thread['broken']: + if debugStatus < 1: + debugStatus = 0 - self.__threadList.header().resizeSections(QHeaderView.ResizeToContents) - self.__threadList.header().setStretchLastSection(True) - - if citm: - self.__doThreadListUpdate = False - self.__threadList.setCurrentItem(citm) - self.__doThreadListUpdate = True - + if debugStatus == -1: + icon = "mediaPlaybackStart.png" + elif debugStatus == 0: + icon = "mediaPlaybackPause.png" + else: + icon = "exceptions.png" + self.__debuggersCombo.setItemIcon(self.__debuggersCombo.currentIndex(), + UI.PixmapCache.getIcon(icon)) + def __threadSelected(self, current, previous): """ Private slot to handle the selection of a thread in the thread list.