#include "listwindow.h" #include "ui_listwindow.h" ListWindow::ListWindow(QWidget *parent) : QDialog(parent), ui(new Ui::ListWindow) { ui->setupUi(this); setWindowTitle("LinkScope - Selector"); treeModel=new QStandardItemModel(ui->tree); ui->tree->setModel(treeModel); gdbProcess=new QProcess(); setGDBState(true);//启动GDB进程 } ListWindow::~ListWindow() { deleteTempFile();//删除临时文件 setGDBState(false);//结束GDB进程 delete gdbProcess; delete treeModel; delete ui; } //设置GDB进程状态 void ListWindow::setGDBState(bool run) { if(run)//启动进程 { gdbProcess->setProgram(QCoreApplication::applicationDirPath()+"/gdb/gdb.exe");//设置程序路径 gdbProcess->setWorkingDirectory(QCoreApplication::applicationDirPath()+"/gdb");//设置工作路径 gdbProcess->setNativeArguments("-q");//设置gdb在安静模式下打开 gdbProcess->start(); runGDBCmd("set confirm off\r\n");//设置不要手动确认 runGDBCmd("set print pretty on\r\n");//设置结构体规范打印 } else//结束进程 { gdbProcess->kill(); } } //向GDB进程发送命令并获取标准输出 QString ListWindow::runGDBCmd(const QString &input) { gdbProcess->readAllStandardOutput(); gdbProcess->write(input.toStdString().c_str()); QString res=""; do{ gdbProcess->waitForReadyRead(); res+=gdbProcess->readAllStandardOutput(); }while(!res.endsWith("(gdb) ")); return res; } //使用GDB检查变量名是否为可展开类型 bool ListWindow::checkCanExpand(const QString &varFullName) { QString whatis=runGDBCmd(QString("whatis %1\r\n").arg(varFullName));//先使用whatis指令判断数组和函数指针 whatis.remove("type = "); whatis.remove("\r\n(gdb) "); if(whatis.contains("[")) return true; if(whatis.contains('(')) return false; QString ptype=runGDBCmd(QString("ptype %1\r\n").arg(varFullName));//再使用ptype指令判断是否是其他可展开类型 ptype.remove("type = "); if(ptype.startsWith("struct")||ptype.startsWith("union")) return true; return false; } //从原始变量列表字符串中解析出变量列表 QStringList ListWindow::parseVarList(const QString &raw) { QStringList list; QRegExp rootRx("\\s([^ (]*\\(\\*|)([^ )]+)(\\)\\(.*\\)|\\s:\\s\\d+|);");//正则匹配模板 rootRx.setMinimal(true);//非贪心匹配 int pos=0; while((pos=rootRx.indexIn(raw,pos))!=-1) { QString name=rootRx.cap(2);//获取截取出的变量名部分 if(name.contains('*'))//手动剔除'*' name.remove('*'); if(name.contains('['))//手动剔除数组长度部分 name.remove(QRegExp("\\[\\d+\\]")); list.append(name); pos+=rootRx.matchedLength(); } return list; } //删除一个原始变量列表字符串中的嵌套部分,跳过前offset个字符 void ListWindow::removeInnerSection(QString &raw,int offset) { for(int startPos=offset;startPosparent->parent)//到父节点为根节点为止 { if(curNode->name.contains('['))//若为数组元素,父节点为数组名,直接拼接(无需加'.') fullName=curNode->parent->name+fullName; else//非数组类型与父节点拼接时还需加一个'.' fullName=curNode->parent->name+'.'+fullName; curNode=curNode->parent;//指针向上移动一层 } return fullName; } //解析一个节点的子节点,并更新子节点的可展开状态 void ListWindow::parseVarChildren(VarNode &node) { if(node.parent==NULL)//传入的是根节点 { QString rawVarList=runGDBCmd("info variables\r\n");//使用info variables指令列出axf中所有变量 QStringList varList=parseVarList(rawVarList);//解析出变量列表 foreach(QString name,varList)//依次添加子节点并更新可展开状态 { node.append(name); node.children.last().canExpand=checkCanExpand(getVarFullName(node.children.last())); } } else//传入的是普通节点 { QString fullName=getVarFullName(node);//计算节点全名 QString rawVarType=runGDBCmd(QString("whatis %1\r\n").arg(fullName));//使用whatis指令获取类型 rawVarType.remove("type = "); rawVarType.remove("\r\n(gdb) "); if(rawVarType.contains("["))//判定是否为数组类型 { QRegExp rx("\\[(\\d+)\\]");//使用正则表达式提取出第一维长度len rx.setMinimal(true); rx.indexIn(rawVarType); int len=rx.cap(1).toInt(); for(int i=0;isetData((qlonglong)&varTree);//将item的数据指向根节点 rootItem->appendRow(new QStandardItem());//附加一个空item让树状图显示为可展开 treeModel->clear();//清理树状图数据 treeModel->appendRow(rootItem);//添加根节点item } //树状图展开槽函数 void ListWindow::on_tree_expanded(const QModelIndex &index) { QStandardItem *item=treeModel->itemFromIndex(index);//获取所展开的item VarNode &node=*(VarNode*)(item->data().toULongLong());//获取对应的节点 if(!node.parsed)//若节点未解析过,则进行解析 { parseVarChildren(node);//解析该节点的子节点,更新各子节点的可展开状态 item->removeRows(0,item->rowCount());//先清空当前item下的所有子项 for(int i=0;isetText(childNode.name);//设定item显示变量名 childItem->setData((qlonglong)&childNode);//建立item到对应节点的寻址方式 if(childNode.canExpand)//若该子节点可展开,则添加一个空item使其显示为可展开状态 childItem->appendRow(new QStandardItem()); item->appendRow(childItem);//子节点item附加到当前被展开的item下 } } } //添加到编辑框按钮槽函数 void ListWindow::on_btn_add2edit_clicked() { QModelIndex index=ui->tree->currentIndex();//获取当前所选index if(index.row()==-1) return; VarNode &node=*(VarNode*)(treeModel->itemFromIndex(index)->data().toULongLong());//获取所选节点 if(node.parent) emit add2Edit(getVarFullName(node));//将变量全名使用信号发出去 } //添加到列表按钮槽函数(逻辑与添加到编辑框相同,仅发送的信号不同) void ListWindow::on_btn_add2list_clicked() { QModelIndex index=ui->tree->currentIndex(); if(index.row()==-1) return; VarNode &node=*(VarNode*)(treeModel->itemFromIndex(index)->data().toULongLong()); if(node.parent) emit add2List(getVarFullName(node)); }