#include #include "ThreadsWidget.h" #include "ui_ThreadsWidget.h" #include "common/JsonModel.h" #include "QuickFilterView.h" #include #include "core/MainWindow.h" #define DEBUGGED_PID (-1) enum ColumnIndex { COLUMN_CURRENT = 0, COLUMN_PID, COLUMN_STATUS, COLUMN_PATH, }; ThreadsWidget::ThreadsWidget(MainWindow *main, QAction *action) : CutterDockWidget(main, action), ui(new Ui::ThreadsWidget) { ui->setupUi(this); // Setup threads model modelThreads = new QStandardItemModel(1, 4, this); modelThreads->setHorizontalHeaderItem(COLUMN_CURRENT, new QStandardItem(tr("Current"))); modelThreads->setHorizontalHeaderItem(COLUMN_PID, new QStandardItem(tr("PID"))); modelThreads->setHorizontalHeaderItem(COLUMN_STATUS, new QStandardItem(tr("Status"))); modelThreads->setHorizontalHeaderItem(COLUMN_PATH, new QStandardItem(tr("Path"))); ui->viewThreads->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter); ui->viewThreads->verticalHeader()->setVisible(false); ui->viewThreads->setFont(Config()->getFont()); modelFilter = new ThreadsFilterModel(this); modelFilter->setSourceModel(modelThreads); ui->viewThreads->setModel(modelFilter); // CTRL+F switches to the filter view and opens it in case it's hidden QShortcut *searchShortcut = new QShortcut(QKeySequence::Find, this); connect(searchShortcut, &QShortcut::activated, ui->quickFilterView, &QuickFilterView::showFilter); searchShortcut->setContext(Qt::WidgetWithChildrenShortcut); // ESC switches back to the thread table and clears the buffer QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this); connect(clearShortcut, &QShortcut::activated, this, [this]() { ui->quickFilterView->clearFilter(); ui->viewThreads->setFocus(); }); clearShortcut->setContext(Qt::WidgetWithChildrenShortcut); refreshDeferrer = createRefreshDeferrer([this]() { updateContents(); }); connect(ui->quickFilterView, &QuickFilterView::filterTextChanged, modelFilter, &ThreadsFilterModel::setFilterWildcard); connect(Core(), &CutterCore::refreshAll, this, &ThreadsWidget::updateContents); connect(Core(), &CutterCore::seekChanged, this, &ThreadsWidget::updateContents); connect(Config(), &Configuration::fontsUpdated, this, &ThreadsWidget::fontsUpdatedSlot); connect(ui->viewThreads, &QTableView::activated, this, &ThreadsWidget::onActivated); } ThreadsWidget::~ThreadsWidget() {} void ThreadsWidget::updateContents() { if (!refreshDeferrer->attemptRefresh(nullptr)) { return; } setThreadsGrid(); if (Core()->isDebugTaskInProgress() || !Core()->currentlyDebugging) { ui->viewThreads->setSelectionMode(QAbstractItemView::NoSelection); } } QString ThreadsWidget::translateStatus(QString status) { switch (status.toStdString().c_str()[0]) { case R_DBG_PROC_STOP: return "Stopped"; case R_DBG_PROC_RUN: return "Running"; case R_DBG_PROC_SLEEP: return "Sleeping"; case R_DBG_PROC_ZOMBIE: return "Zombie"; case R_DBG_PROC_DEAD: return "Dead"; case R_DBG_PROC_RAISED: return "Raised event"; default: return "Unknown status"; } } void ThreadsWidget::setThreadsGrid() { QJsonArray threadsValues = Core()->getProcessThreads(DEBUGGED_PID).array(); int i = 0; for (const QJsonValue &value : threadsValues) { QJsonObject threadsItem = value.toObject(); int pid = threadsItem["pid"].toVariant().toInt(); QString status = translateStatus(threadsItem["status"].toString()); QString path = threadsItem["path"].toString(); bool current = threadsItem["current"].toBool(); QStandardItem *rowCurrent = new QStandardItem(QString(current ? "True" : "False")); QStandardItem *rowPid = new QStandardItem(QString::number(pid)); QStandardItem *rowStatus = new QStandardItem(status); QStandardItem *rowPath = new QStandardItem(path); modelThreads->setItem(i, COLUMN_CURRENT, rowCurrent); modelThreads->setItem(i, COLUMN_PID, rowPid); modelThreads->setItem(i, COLUMN_STATUS, rowStatus); modelThreads->setItem(i, COLUMN_PATH, rowPath); i++; } // Remove irrelevant old rows if (modelThreads->rowCount() > i) { modelThreads->removeRows(i, modelThreads->rowCount() - i); } modelFilter->setSourceModel(modelThreads); ui->viewThreads->resizeColumnsToContents();; } void ThreadsWidget::fontsUpdatedSlot() { ui->viewThreads->setFont(Config()->getFont()); } void ThreadsWidget::onActivated(const QModelIndex &index) { if (!index.isValid()) return; int tid = modelFilter->data(index.sibling(index.row(), COLUMN_PID)).toInt(); // Verify that the selected tid is still in the threads list since dpt= will // attach to any given id. If it isn't found simply update the UI. QJsonArray threadsValues = Core()->getProcessThreads(DEBUGGED_PID).array(); for (QJsonValue value : threadsValues) { if (tid == value.toObject()["pid"].toInt()) { Core()->setCurrentDebugThread(tid); break; } } updateContents(); } ThreadsFilterModel::ThreadsFilterModel(QObject *parent) : QSortFilterProxyModel(parent) { setFilterCaseSensitivity(Qt::CaseInsensitive); setSortCaseSensitivity(Qt::CaseInsensitive); } bool ThreadsFilterModel::filterAcceptsRow(int row, const QModelIndex &parent) const { // All columns are checked for a match for (int i = COLUMN_CURRENT; i <= COLUMN_PATH; ++i) { QModelIndex index = sourceModel()->index(row, i, parent); if (sourceModel()->data(index).toString().contains(filterRegExp())) { return true; } } return false; }