21 """ |
21 """ |
22 |
22 |
23 |
23 |
24 import os |
24 import os |
25 |
25 |
26 from PyQt5.QtCore import pyqtSignal |
26 from PyQt5.QtCore import pyqtSignal, Qt |
27 from PyQt5.QtWidgets import ( |
27 from PyQt5.QtWidgets import ( |
28 QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QSizePolicy, QPushButton, |
28 QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QSizePolicy, QPushButton, |
29 QComboBox, QLabel, QTreeWidget, QTreeWidgetItem, QHeaderView, QFrame |
29 QComboBox, QLabel, QTreeWidget, QTreeWidgetItem, QHeaderView, QFrame |
30 ) |
30 ) |
31 |
31 |
67 self.__mainLayout = QVBoxLayout() |
67 self.__mainLayout = QVBoxLayout() |
68 self.__mainLayout.setContentsMargins(0, 0, 0, 0) |
68 self.__mainLayout.setContentsMargins(0, 0, 0, 0) |
69 self.setLayout(self.__mainLayout) |
69 self.setLayout(self.__mainLayout) |
70 |
70 |
71 # add the viewer showing the connected debug backends |
71 # add the viewer showing the connected debug backends |
72 self.__debuggersLayout = QHBoxLayout(self) |
72 self.__debuggersLayout = QHBoxLayout() |
73 self.__debuggersLayout.addWidget(QLabel(self.tr("Debuggers:"))) |
73 self.__debuggersLayout.addWidget(QLabel(self.tr("Debuggers:"))) |
74 self.__debuggersCombo = QComboBox(self) |
74 self.__debuggersCombo = QComboBox(self) |
75 self.__debuggersCombo.setSizePolicy( |
75 self.__debuggersCombo.setSizePolicy( |
76 QSizePolicy.Expanding, QSizePolicy.Fixed) |
76 QSizePolicy.Expanding, QSizePolicy.Fixed) |
77 self.__debuggersLayout.addWidget(self.__debuggersCombo) |
77 self.__debuggersLayout.addWidget(self.__debuggersCombo) |
78 self.__mainLayout.addLayout(self.__debuggersLayout) |
78 self.__mainLayout.addLayout(self.__debuggersLayout) |
79 |
79 |
80 self.__debuggersCombo.currentTextChanged.connect( |
80 self.__debuggersCombo.currentIndexChanged[str].connect( |
81 self.__debuggerSelected) |
81 self.__debuggerSelected) |
82 |
82 |
83 # add a line to separate debugger selector from debugger specific parts |
83 # add a line to separate debugger selector from debugger specific parts |
84 hline = QFrame(self) |
84 hline = QFrame(self) |
85 hline.setFrameStyle(QFrame.Sunken) |
85 hline.setFrameStyle(QFrame.Sunken) |
262 self.__mainLayout.setStretchFactor(self.__threadList, 1) |
262 self.__mainLayout.setStretchFactor(self.__threadList, 1) |
263 |
263 |
264 self.currentStack = None |
264 self.currentStack = None |
265 self.framenr = 0 |
265 self.framenr = 0 |
266 |
266 |
267 self.debugServer.clientStack.connect(self.handleClientStack) |
|
268 |
|
269 self.__autoViewSource = Preferences.getDebugger("AutoViewSourceCode") |
267 self.__autoViewSource = Preferences.getDebugger("AutoViewSourceCode") |
270 self.sourceButton.setVisible(not self.__autoViewSource) |
268 self.sourceButton.setVisible(not self.__autoViewSource) |
271 |
269 |
|
270 # connect somer debug server signals |
|
271 self.debugServer.clientStack.connect( |
|
272 self.handleClientStack) |
|
273 self.debugServer.clientThreadList.connect( |
|
274 self.showThreadList) |
|
275 self.debugServer.clientDebuggerIds.connect( |
|
276 self.showDebuggersList) |
|
277 self.debugServer.passiveDebugStarted.connect( |
|
278 self.handleDebuggingStarted) |
|
279 self.debugServer.clientLine.connect( |
|
280 self.__clientLine) |
|
281 |
|
282 self.debugServer.clientException.connect( |
|
283 self.exceptionLogger.addException) |
|
284 self.debugServer.passiveDebugStarted.connect( |
|
285 self.exceptionLogger.debuggingStarted) |
|
286 |
|
287 self.debugServer.clientLine.connect( |
|
288 self.breakpointViewer.highlightBreakpoint) |
|
289 |
272 def handlePreferencesChanged(self): |
290 def handlePreferencesChanged(self): |
273 """ |
291 """ |
274 Public slot to handle the preferencesChanged signal. |
292 Public slot to handle the preferencesChanged signal. |
275 """ |
293 """ |
276 self.__autoViewSource = Preferences.getDebugger("AutoViewSourceCode") |
294 self.__autoViewSource = Preferences.getDebugger("AutoViewSourceCode") |
281 Public method to set a reference to the Debug UI. |
299 Public method to set a reference to the Debug UI. |
282 |
300 |
283 @param debugUI reference to the DebugUI object (DebugUI) |
301 @param debugUI reference to the DebugUI object (DebugUI) |
284 """ |
302 """ |
285 self.debugUI = debugUI |
303 self.debugUI = debugUI |
|
304 self.callStackViewer.setDebugger(debugUI) |
|
305 |
|
306 # connect some debugUI signals |
286 self.debugUI.clientStack.connect(self.handleClientStack) |
307 self.debugUI.clientStack.connect(self.handleClientStack) |
287 self.callStackViewer.setDebugger(debugUI) |
308 self.debugUI.debuggingStarted.connect( |
288 |
309 self.exceptionLogger.debuggingStarted) |
|
310 self.debugUI.debuggingStarted.connect( |
|
311 self.handleDebuggingStarted) |
|
312 |
289 def handleResetUI(self): |
313 def handleResetUI(self): |
290 """ |
314 """ |
291 Public method to reset the SBVviewer. |
315 Public method to reset the SBVviewer. |
292 """ |
316 """ |
293 self.globalsViewer.handleResetUI() |
317 self.globalsViewer.handleResetUI() |
369 if showGlobals: |
393 if showGlobals: |
370 self.__tabWidget.setCurrentWidget(self.glvWidget) |
394 self.__tabWidget.setCurrentWidget(self.glvWidget) |
371 else: |
395 else: |
372 self.__tabWidget.setCurrentWidget(self.lvWidget) |
396 self.__tabWidget.setCurrentWidget(self.lvWidget) |
373 |
397 |
374 def handleClientStack(self, stack): |
398 def handleClientStack(self, stack, debuggerId): |
375 """ |
399 """ |
376 Public slot to show the call stack of the program being debugged. |
400 Public slot to show the call stack of the program being debugged. |
377 |
401 |
378 @param stack list of tuples with call stack data (file name, |
402 @param stack list of tuples with call stack data (file name, |
379 line number, function name, formatted argument/values list) |
403 line number, function name, formatted argument/values list) |
380 """ |
404 @type list of tuples of (str, str, str, str) |
381 block = self.stackComboBox.blockSignals(True) |
405 @param debuggerId ID of the debugger backend |
382 self.framenr = 0 |
406 @type str |
383 self.stackComboBox.clear() |
407 """ |
384 self.currentStack = stack |
408 if debuggerId == self.__debuggersCombo.currentText(): |
385 self.sourceButton.setEnabled(len(stack) > 0) |
409 block = self.stackComboBox.blockSignals(True) |
386 for s in stack: |
410 self.framenr = 0 |
387 # just show base filename to make it readable |
411 self.stackComboBox.clear() |
388 s = (os.path.basename(s[0]), s[1], s[2]) |
412 self.currentStack = stack |
389 self.stackComboBox.addItem('{0}:{1}:{2}'.format(*s)) |
413 self.sourceButton.setEnabled(len(stack) > 0) |
390 self.stackComboBox.blockSignals(block) |
414 for s in stack: |
391 |
415 # just show base filename to make it readable |
|
416 s = (os.path.basename(s[0]), s[1], s[2]) |
|
417 self.stackComboBox.addItem('{0}:{1}:{2}'.format(*s)) |
|
418 self.stackComboBox.blockSignals(block) |
|
419 |
|
420 def __clientLine(self, fn, line, debuggerId): |
|
421 """ |
|
422 Private method to handle a change to the current line. |
|
423 |
|
424 @param fn filename |
|
425 @type str |
|
426 @param line linenumber |
|
427 @type int |
|
428 @param debuggerId ID of the debugger backend |
|
429 @type str |
|
430 """ |
|
431 if debuggerId: |
|
432 index = self.__debuggersCombo.findText(debuggerId, Qt.MatchExactly) |
|
433 if index >= 0: |
|
434 self.__debuggersCombo.setItemIcon( |
|
435 index, UI.PixmapCache.getIcon("exceptions.png")) |
|
436 |
392 def setVariablesFilter(self, globalsFilter, localsFilter): |
437 def setVariablesFilter(self, globalsFilter, localsFilter): |
393 """ |
438 """ |
394 Public slot to set the local variables filter. |
439 Public slot to set the local variables filter. |
395 |
440 |
396 @param globalsFilter filter list for global variable types |
441 @param globalsFilter filter list for global variable types |
469 |
514 |
470 @param widget reference to the widget (QWidget) |
515 @param widget reference to the widget (QWidget) |
471 """ |
516 """ |
472 self.__tabWidget.setCurrentWidget(widget) |
517 self.__tabWidget.setCurrentWidget(widget) |
473 |
518 |
474 def showThreadList(self, currentID, threadList): |
519 def showThreadList(self, currentID, threadList, debuggerId): |
475 """ |
520 """ |
476 Public method to show the thread list. |
521 Public method to show the thread list. |
477 |
522 |
478 @param currentID id of the current thread (integer) |
523 @param currentID id of the current thread |
|
524 @type int |
479 @param threadList list of dictionaries containing the thread data |
525 @param threadList list of dictionaries containing the thread data |
480 """ |
526 @type list of dict |
481 citm = None |
527 @param debuggerId ID of the debugger backend |
482 |
528 @type str |
483 self.__threadList.clear() |
529 """ |
484 for thread in threadList: |
530 debugStatus = -1 # i.e. running |
485 if thread.get('except', False): |
531 |
486 state = self.tr("waiting at exception") |
532 if debuggerId == self.__debuggersCombo.currentText(): |
487 icon = "exceptions.png" |
533 citm = None |
488 elif thread['broken']: |
534 |
489 state = self.tr("waiting at breakpoint") |
535 self.__threadList.clear() |
490 icon = "mediaPlaybackPause.png" |
536 for thread in threadList: |
491 else: |
537 if thread.get('except', False): |
492 state = self.tr("running") |
538 state = self.tr("waiting at exception") |
493 icon = "mediaPlaybackStart.png" |
539 icon = "exceptions.png" |
494 itm = QTreeWidgetItem(self.__threadList, |
540 debugStatus = 1 |
495 ["{0:d}".format(thread['id']), |
541 elif thread['broken']: |
496 thread['name'], state]) |
542 state = self.tr("waiting at breakpoint") |
497 itm.setIcon(0, UI.PixmapCache.getIcon(icon)) |
543 icon = "mediaPlaybackPause.png" |
498 if thread['id'] == currentID: |
544 if debugStatus < 1: |
499 citm = itm |
545 debugStatus = 0 |
500 |
546 else: |
501 self.__threadList.header().resizeSections(QHeaderView.ResizeToContents) |
547 state = self.tr("running") |
502 self.__threadList.header().setStretchLastSection(True) |
548 icon = "mediaPlaybackStart.png" |
503 |
549 itm = QTreeWidgetItem(self.__threadList, |
504 if citm: |
550 ["{0:d}".format(thread['id']), |
505 self.__doThreadListUpdate = False |
551 thread['name'], state]) |
506 self.__threadList.setCurrentItem(citm) |
552 itm.setIcon(0, UI.PixmapCache.getIcon(icon)) |
507 self.__doThreadListUpdate = True |
553 if thread['id'] == currentID: |
508 |
554 citm = itm |
|
555 |
|
556 self.__threadList.header().resizeSections( |
|
557 QHeaderView.ResizeToContents) |
|
558 self.__threadList.header().setStretchLastSection(True) |
|
559 |
|
560 if citm: |
|
561 self.__doThreadListUpdate = False |
|
562 self.__threadList.setCurrentItem(citm) |
|
563 self.__doThreadListUpdate = True |
|
564 else: |
|
565 for thread in threadList: |
|
566 if thread.get('except', False): |
|
567 debugStatus = 1 |
|
568 elif thread['broken']: |
|
569 if debugStatus < 1: |
|
570 debugStatus = 0 |
|
571 |
|
572 if debugStatus == -1: |
|
573 icon = "mediaPlaybackStart.png" |
|
574 elif debugStatus == 0: |
|
575 icon = "mediaPlaybackPause.png" |
|
576 else: |
|
577 icon = "exceptions.png" |
|
578 self.__debuggersCombo.setItemIcon(self.__debuggersCombo.currentIndex(), |
|
579 UI.PixmapCache.getIcon(icon)) |
|
580 |
509 def __threadSelected(self, current, previous): |
581 def __threadSelected(self, current, previous): |
510 """ |
582 """ |
511 Private slot to handle the selection of a thread in the thread list. |
583 Private slot to handle the selection of a thread in the thread list. |
512 |
584 |
513 @param current reference to the new current item (QTreeWidgetItem) |
585 @param current reference to the new current item (QTreeWidgetItem) |