From 984d10eaf10337df828ac87e37b20846b41cb5de Mon Sep 17 00:00:00 2001 From: Roy Qu Date: Sun, 16 Oct 2022 23:10:57 +0800 Subject: [PATCH] - enhancement: project and non-project files use different breakpoint and watchvar view (auto switch when not debugging and editor switched) - enhancement: save project's breakpoint and watchvar in it's own debug file. - enhancement: delete a watch expression don't reload who watch var view --- NEWS.md | 4 +- RedPandaIDE/debugger.cpp | 724 ++++++++++++------ RedPandaIDE/debugger.h | 127 ++- RedPandaIDE/editor.cpp | 12 +- RedPandaIDE/mainwindow.cpp | 90 +-- RedPandaIDE/settings.cpp | 24 +- RedPandaIDE/settings.h | 12 +- .../settingsdialog/debuggeneralwidget.cpp | 6 +- .../settingsdialog/debuggeneralwidget.ui | 11 +- RedPandaIDE/systemconsts.h | 4 +- RedPandaIDE/widgets/bookmarkmodel.cpp | 9 +- RedPandaIDE/widgets/cpudialog.cpp | 2 +- 12 files changed, 633 insertions(+), 392 deletions(-) diff --git a/NEWS.md b/NEWS.md index f62f9c52..ebf05939 100644 --- a/NEWS.md +++ b/NEWS.md @@ -16,7 +16,9 @@ Red Panda C++ Version 1.5 - fix: icons in options dialogs not correctly updated when change icon set - enhancement: set compilation stage in the options / compiler set pages - enhancement: set custom compilation output suffix in the options / compiler set pages - + - enhancement: project and non-project files use different breakpoint and watchvar view (auto switch when not debugging and editor switched) + - enhancement: save project's breakpoint and watchvar in it's own debug file. + - enhancement: delete a watch expression don't reload who watch var view Red Panda C++ Version 1.4 diff --git a/RedPandaIDE/debugger.cpp b/RedPandaIDE/debugger.cpp index ac29bd30..b45342e9 100644 --- a/RedPandaIDE/debugger.cpp +++ b/RedPandaIDE/debugger.cpp @@ -34,18 +34,20 @@ #include "widgets/signalmessagedialog.h" Debugger::Debugger(QObject *parent) : QObject(parent), - mForceUTF8(false) + mForceUTF8(false), + mLastLoadtime(0), + mProjectLastLoadtime(0) { //models deleted in the destructor - mBreakpointModel=new BreakpointModel(this); - mBacktraceModel=new BacktraceModel(this); - mWatchModel = new WatchModel(this); - mRegisterModel = new RegisterModel(this); - mMemoryModel = new MemoryModel(8,this); + mBreakpointModel= std::make_shared(this); + mBacktraceModel = std::make_shared(this); + mWatchModel = std::make_shared(this); + mRegisterModel = std::make_shared(this); + mMemoryModel = std::make_shared(8,this); - connect(mMemoryModel,&MemoryModel::setMemoryData, + connect(mMemoryModel.get(),&MemoryModel::setMemoryData, this, &Debugger::setMemoryData); - connect(mWatchModel, &WatchModel::setWatchVarValue, + connect(mWatchModel.get(), &WatchModel::setWatchVarValue, this, &Debugger::setWatchVarValue); mExecuting = false; mReader = nullptr; @@ -53,17 +55,19 @@ Debugger::Debugger(QObject *parent) : QObject(parent), mCommandChanged = false; mLeftPageIndexBackup = -1; - connect(mWatchModel, &WatchModel::fetchChildren, + connect(mWatchModel.get(), &WatchModel::fetchChildren, this, &Debugger::fetchVarChildren); + + setIsForProject(false); } Debugger::~Debugger() { - delete mBreakpointModel; - delete mBacktraceModel; - delete mWatchModel; - delete mRegisterModel; - delete mMemoryModel; +// delete mBreakpointModel; +// delete mBacktraceModel; +// delete mWatchModel; +// delete mRegisterModel; +// delete mMemoryModel; } bool Debugger::start(int compilerSetIndex, const QString& inferior, const QStringList& binDirs) @@ -145,14 +149,14 @@ bool Debugger::start(int compilerSetIndex, const QString& inferior, const QStrin mReader->addBinDir(pSettings->dirs().appDir()); mReader->setDebuggerPath(debuggerPath); connect(mReader, &QThread::finished,this,&Debugger::cleanUpReader); - connect(mReader, &QThread::finished,mMemoryModel,&MemoryModel::reset); + connect(mReader, &QThread::finished,mMemoryModel.get(),&MemoryModel::reset); connect(mReader, &DebugReader::parseFinished,this,&Debugger::syncFinishedParsing,Qt::BlockingQueuedConnection); connect(mReader, &DebugReader::changeDebugConsoleLastLine,this,&Debugger::onChangeDebugConsoleLastline); connect(mReader, &DebugReader::cmdStarted,pMainWindow, &MainWindow::disableDebugActions); connect(mReader, &DebugReader::cmdFinished,pMainWindow, &MainWindow::enableDebugActions); connect(mReader, &DebugReader::inferiorStopped, pMainWindow, &MainWindow::enableDebugActions); - connect(mReader, &DebugReader::breakpointInfoGetted, mBreakpointModel, + connect(mReader, &DebugReader::breakpointInfoGetted, mBreakpointModel.get(), &BreakpointModel::updateBreakpointNumber); connect(mReader, &DebugReader::localsUpdated, pMainWindow, &MainWindow::onLocalsReady); @@ -166,15 +170,15 @@ bool Debugger::start(int compilerSetIndex, const QString& inferior, const QStrin &Debugger::updateRegisterNames); connect(mReader, &DebugReader::registerValuesUpdated, this, &Debugger::updateRegisterValues); - connect(mReader, &DebugReader::varCreated,mWatchModel, + connect(mReader, &DebugReader::varCreated,mWatchModel.get(), &WatchModel::updateVarInfo); - connect(mReader, &DebugReader::prepareVarChildren,mWatchModel, + connect(mReader, &DebugReader::prepareVarChildren,mWatchModel.get(), &WatchModel::prepareVarChildren); - connect(mReader, &DebugReader::addVarChild,mWatchModel, + connect(mReader, &DebugReader::addVarChild,mWatchModel.get(), &WatchModel::addVarChild); - connect(mReader, &DebugReader::varValueUpdated,mWatchModel, + connect(mReader, &DebugReader::varValueUpdated,mWatchModel.get(), &WatchModel::updateVarValue); - connect(mReader, &DebugReader::varsValueUpdated,mWatchModel, + connect(mReader, &DebugReader::varsValueUpdated,mWatchModel.get(), &WatchModel::updateAllHasMoreVars); connect(mReader, &DebugReader::inferiorContinued,pMainWindow, &MainWindow::removeActiveBreakpoints); @@ -255,12 +259,12 @@ void Debugger::refreshAll() ); } -RegisterModel *Debugger::registerModel() const +std::shared_ptr Debugger::registerModel() const { return mRegisterModel; } -WatchModel *Debugger::watchModel() const +std::shared_ptr Debugger::watchModel() const { return mWatchModel; } @@ -293,12 +297,25 @@ void Debugger::interrupt() sendCommand("-exec-interrupt", ""); } -void Debugger::addBreakpoint(int line, const Editor* editor) +bool Debugger::isForProject() const { - addBreakpoint(line,editor->filename()); + return mBreakpointModel->isForProject(); } -void Debugger::addBreakpoint(int line, const QString &filename) +void Debugger::setIsForProject(bool newIsForProject) +{ + if (!executing()) { + mBreakpointModel->setIsForProject(newIsForProject); + mWatchModel->setIsForProject(newIsForProject); + } +} + +void Debugger::addBreakpoint(int line, const Editor* editor) +{ + addBreakpoint(line,editor->filename(), editor->inProject()); +} + +void Debugger::addBreakpoint(int line, const QString &filename, bool forProject) { PBreakpoint bp=std::make_shared(); bp->number = -1; @@ -307,76 +324,80 @@ void Debugger::addBreakpoint(int line, const QString &filename) bp->condition = ""; bp->enabled = true; bp->breakpointType = BreakpointType::Breakpoint; - mBreakpointModel->addBreakpoint(bp); + bp->timestamp = QDateTime::currentMSecsSinceEpoch(); + mBreakpointModel->addBreakpoint(bp,forProject); if (mExecuting) { sendBreakpointCommand(bp); } } -void Debugger::deleteBreakpoints(const QString &filename) +void Debugger::deleteBreakpoints(const QString &filename, bool forProject) { - for (int i=mBreakpointModel->breakpoints().size()-1;i>=0;i--) { - PBreakpoint bp = mBreakpointModel->breakpoints()[i]; + const QList& list=mBreakpointModel->breakpoints(forProject); + for (int i=list.size()-1;i>=0;i--) { + PBreakpoint bp = list[i]; if (bp->filename == filename) { - mBreakpointModel->removeBreakpoint(i); + mBreakpointModel->removeBreakpoint(i,forProject); } } } void Debugger::deleteBreakpoints(const Editor *editor) { - deleteBreakpoints(editor->filename()); + deleteBreakpoints(editor->filename(),editor->inProject()); } -void Debugger::deleteBreakpoints() +void Debugger::deleteBreakpoints(bool forProject) { - for (int i=mBreakpointModel->breakpoints().size()-1;i>=0;i--) { - removeBreakpoint(i); - } + mBreakpointModel->clear(forProject); +// for (int i=mBreakpointModel->breakpoints().size()-1;i>=0;i--) { +// removeBreakpoint(i); +// } } void Debugger::removeBreakpoint(int line, const Editor *editor) { - removeBreakpoint(line,editor->filename()); + removeBreakpoint(line,editor->filename(),editor->inProject()); } -void Debugger::removeBreakpoint(int line, const QString &filename) +void Debugger::removeBreakpoint(int line, const QString &filename, bool forProject) { - for (int i=mBreakpointModel->breakpoints().size()-1;i>=0;i--) { - PBreakpoint bp = mBreakpointModel->breakpoints()[i]; + const QList& breakpoints=mBreakpointModel->breakpoints(forProject); + for (int i=breakpoints.size()-1;i>=0;i--) { + PBreakpoint bp = breakpoints[i]; if (bp->filename == filename && bp->line == line) { - removeBreakpoint(i); + removeBreakpoint(i, forProject); } } } -void Debugger::removeBreakpoint(int index) +void Debugger::removeBreakpoint(int index, bool forProject) { - sendClearBreakpointCommand(index); - mBreakpointModel->removeBreakpoint(index); + sendClearBreakpointCommand(index, forProject); + mBreakpointModel->removeBreakpoint(index, forProject); } -PBreakpoint Debugger::breakpointAt(int line, const QString& filename, int &index) +PBreakpoint Debugger::breakpointAt(int line, const QString& filename, int *index , bool forProject) { - const QList& breakpoints=mBreakpointModel->breakpoints(); - for (index=0;index& breakpoints=mBreakpointModel->breakpoints(forProject); + for (*index=0;*indexline == line && breakpoint->filename == filename) return breakpoint; } - index=-1; + *index=-1; return PBreakpoint(); } -PBreakpoint Debugger::breakpointAt(int line, const Editor *editor, int &index) +PBreakpoint Debugger::breakpointAt(int line, const Editor *editor, int *index) { - return breakpointAt(line,editor->filename(),index); + return breakpointAt(line,editor->filename(),index, editor->inProject()); } -void Debugger::setBreakPointCondition(int index, const QString &condition) +void Debugger::setBreakPointCondition(int index, const QString &condition, bool forProject) { - PBreakpoint breakpoint=mBreakpointModel->setBreakPointCondition(index,condition); + PBreakpoint breakpoint=mBreakpointModel->setBreakPointCondition(index,condition, forProject); if (condition.isEmpty()) { sendCommand("-break-condition", QString("%1").arg(breakpoint->number)); @@ -388,11 +409,45 @@ void Debugger::setBreakPointCondition(int index, const QString &condition) void Debugger::sendAllBreakpointsToDebugger() { - for (PBreakpoint breakpoint:mBreakpointModel->breakpoints()) { + for (PBreakpoint breakpoint:mBreakpointModel->breakpoints(mBreakpointModel->isForProject())) { sendBreakpointCommand(breakpoint); } } +void Debugger::saveForNonproject(const QString &filename) +{ + save(filename,QString()); +} + +void Debugger::saveForProject(const QString &filename, const QString &projectFolder) +{ + save(filename,projectFolder); +} + +void Debugger::loadForNonproject(const QString &filename) +{ + bool forProject = false; + PDebugConfig pConfig = load(filename, forProject); + if (pConfig->timestamp>0) { + mBreakpointModel->setBreakpoints(pConfig->breakpoints,forProject); + mWatchModel->setWatchVars(pConfig->watchVars,forProject); + } +} + +void Debugger::loadForProject(const QString &filename, const QString &projectFolder) +{ + bool forProject = false; + PDebugConfig pConfig = load(filename, forProject); + if (pConfig->timestamp>0) { + QDir dir(projectFolder); + foreach (const PBreakpoint& breakpoint, pConfig->breakpoints) { + breakpoint->filename = dir.absoluteFilePath(breakpoint->filename); + } + mBreakpointModel->setBreakpoints(pConfig->breakpoints,forProject); + mWatchModel->setWatchVars(pConfig->watchVars,forProject); + } +} + void Debugger::addWatchVar(const QString &expression) { // Don't allow duplicates... @@ -401,12 +456,12 @@ void Debugger::addWatchVar(const QString &expression) return; PWatchVar var = std::make_shared(); - var->parent= nullptr; + var->parent= PWatchVar(); var->expression = expression; var->value = tr("Execute to evaluate"); var->numChild = 0; var->hasMore = false; - var->parent = nullptr; + var->timestamp = QDateTime::currentMSecsSinceEpoch(); mWatchModel->addWatchVar(var); sendWatchCommand(var); @@ -462,7 +517,7 @@ void Debugger::setForceUTF8(bool newForceUTF8) mForceUTF8 = newForceUTF8; } -MemoryModel *Debugger::memoryModel() const +std::shared_ptr Debugger::memoryModel() const { return mMemoryModel; } @@ -510,12 +565,12 @@ PWatchVar Debugger::watchVarAt(const QModelIndex &index) //{ // mWatchModel->notifyUpdated(var); //} -BacktraceModel* Debugger::backtraceModel() +std::shared_ptr Debugger::backtraceModel() { return mBacktraceModel; } -BreakpointModel *Debugger::breakpointModel() +std::shared_ptr Debugger::breakpointModel() { return mBreakpointModel; } @@ -547,9 +602,9 @@ void Debugger::sendBreakpointCommand(PBreakpoint breakpoint) } } -void Debugger::sendClearBreakpointCommand(int index) +void Debugger::sendClearBreakpointCommand(int index, bool forProject) { - sendClearBreakpointCommand(mBreakpointModel->breakpoints()[index]); + sendClearBreakpointCommand(mBreakpointModel->breakpoints(forProject)[index]); } void Debugger::sendClearBreakpointCommand(PBreakpoint breakpoint) @@ -564,6 +619,148 @@ void Debugger::sendClearBreakpointCommand(PBreakpoint breakpoint) } } +QJsonArray BreakpointModel::toJson(const QString& projectFolder) +{ + bool forProject = !projectFolder.isEmpty(); + QJsonArray array; + foreach (const PBreakpoint& breakpoint, breakpoints(forProject)) { + QJsonObject obj; + if (forProject) + obj["filename"]=extractRelativePath(projectFolder, breakpoint->filename); + else + obj["filename"]=breakpoint->filename; + obj["line"]=breakpoint->line; + obj["condition"]=breakpoint->condition; + obj["enabled"]=breakpoint->enabled; + obj["breakpoint_type"] = static_cast(breakpoint->breakpointType); + obj["timestamp"]=QString("%1").arg(breakpoint->timestamp); + array.append(obj); + } + return array; +} + +void BreakpointModel::setBreakpoints(const QList &list, bool forProject) +{ + if (mIsForProject == forProject) + beginResetModel(); + if (forProject) { + mProjectBreakpoints = list; + } else { + mBreakpoints = list; + } + if (mIsForProject == forProject) + endResetModel(); +} + +void Debugger::save(const QString &filename, const QString& projectFolder) +{ + bool forProject=!projectFolder.isEmpty(); + QList breakpoints; + QList watchVars=mWatchModel->watchVars(forProject); + QSet breakpointCompareSet; + QSet watchVarCompareSet; + if (forProject) { + //convert project file's absolute path to relative path + foreach (const PBreakpoint& breakpoint, mBreakpointModel->breakpoints(forProject)) { + QString filename = extractRelativePath(projectFolder, breakpoint->filename); + QString key = QString("%1-%2").arg(filename).arg(breakpoint->line); + breakpointCompareSet.insert(key); + } + } else { + foreach (const PBreakpoint& breakpoint, mBreakpointModel->breakpoints(forProject)) { + QString key = QString("%1-%2").arg(breakpoint->filename).arg(breakpoint->line); + breakpointCompareSet.insert(key); + } + } + foreach (const PWatchVar& watchVar, watchVars) { + watchVarCompareSet.insert(watchVar->expression); + } + std::shared_ptr pConfig = load(filename, forProject); + QFile file(filename); + if (file.open(QFile::WriteOnly | QFile::Truncate)) { + QDir folder(projectFolder); + foreach (const PBreakpoint& breakpoint, pConfig->breakpoints) { + QString key = QString("%1-%2").arg(breakpoint->filename).arg(breakpoint->line); + if (!breakpointCompareSet.contains(key)) { + breakpointCompareSet.insert(key); + if (forProject) + breakpoint->filename=folder.absoluteFilePath(breakpoint->filename); + mBreakpointModel->addBreakpoint(breakpoint,forProject); + } + } + foreach (const PWatchVar& watchVar, pConfig->watchVars) { + QString key = watchVar->expression; + if (!watchVarCompareSet.contains(key)) { + watchVarCompareSet.insert(key); + addWatchVar(key); + } + } + qint64 saveTimestamp = QDateTime::currentMSecsSinceEpoch();; + if (forProject) { + mProjectLastLoadtime = saveTimestamp; + } else { + mLastLoadtime = saveTimestamp; + } + QJsonObject rootObj; + rootObj["timestamp"] = QString("%1").arg(saveTimestamp); + + rootObj["breakpoints"] = mBreakpointModel->toJson(projectFolder); + rootObj["watchvars"] = mWatchModel->toJson(forProject); + QJsonDocument doc; + doc.setObject(rootObj); + if (file.write(doc.toJson())<0) { + throw FileError(tr("Save file '%1' failed.") + .arg(filename)); + } + } else { + throw FileError(tr("Can't open file '%1' for write.") + .arg(filename)); + } +} + +PDebugConfig Debugger::load(const QString &filename, bool forProject) +{ + qint64 criteriaTimestamp; + if (forProject) { + criteriaTimestamp = mProjectLastLoadtime; + } else { + criteriaTimestamp = mLastLoadtime; + } + std::shared_ptr pConfig=std::make_shared(); + pConfig->timestamp=0; + QFile file(filename); + if (!file.exists()) + return pConfig; + if (file.open(QFile::ReadOnly)) { + QByteArray content = file.readAll(); + QJsonParseError error; + QJsonDocument doc(QJsonDocument::fromJson(content,&error)); + if (error.error != QJsonParseError::NoError) { + throw FileError(tr("Error in json file '%1':%2 : %3") + .arg(filename) + .arg(error.offset) + .arg(error.errorString())); + } + QJsonObject rootObject = doc.object(); + qint64 timestamp = rootObject["timestamp"].toString().toLongLong(); + if (timestamp <= criteriaTimestamp) + return pConfig; + pConfig->timestamp = timestamp; + + pConfig->breakpoints = mBreakpointModel->loadJson(rootObject["breakpoints"].toArray(),criteriaTimestamp); + pConfig->watchVars = mWatchModel->loadJson(rootObject["watchvars"].toArray(), criteriaTimestamp); + if (forProject) { + mProjectLastLoadtime = QDateTime::currentMSecsSinceEpoch(); + } else { + mLastLoadtime = QDateTime::currentMSecsSinceEpoch(); + } + } else { + throw FileError(tr("Can't open file '%1' for read.") + .arg(filename)); + } + return pConfig; +} + void Debugger::syncFinishedParsing() { bool spawnedcpuform = false; @@ -1524,7 +1721,7 @@ BreakpointModel::BreakpointModel(QObject *parent):QAbstractTableModel(parent) int BreakpointModel::rowCount(const QModelIndex &) const { - return mList.size(); + return breakpoints(mIsForProject).size(); } int BreakpointModel::columnCount(const QModelIndex &) const @@ -1536,9 +1733,11 @@ QVariant BreakpointModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); - if (index.row()<0 || index.row() >= static_cast(mList.size())) + const QList &list=breakpoints(mIsForProject); + if (index.row()<0 || index.row() >= static_cast(list.size())) return QVariant(); - PBreakpoint breakpoint = mList[index.row()]; + + PBreakpoint breakpoint = list[index.row()]; if (!breakpoint) return QVariant(); switch (role) { @@ -1591,119 +1790,78 @@ QVariant BreakpointModel::headerData(int section, Qt::Orientation orientation, i return QVariant(); } -void BreakpointModel::addBreakpoint(PBreakpoint p) +void BreakpointModel::addBreakpoint(PBreakpoint p, bool forProject) { - beginInsertRows(QModelIndex(),mList.size(),mList.size()); - mList.push_back(p); - endInsertRows(); + + if (forProject) { + if (forProject==mIsForProject) + beginInsertRows(QModelIndex(),mProjectBreakpoints.count(),mProjectBreakpoints.count()); + mProjectBreakpoints.push_back(p); + } else { + if (forProject==mIsForProject) + beginInsertRows(QModelIndex(),mBreakpoints.count(),mBreakpoints.count()); + mBreakpoints.push_back(p); + } + if (forProject==mIsForProject) + endInsertRows(); } -void BreakpointModel::clear() +void BreakpointModel::clear(bool forProject) { - beginResetModel(); - mList.clear(); - endResetModel(); + if (forProject == mIsForProject) + beginResetModel(); + if (forProject) + mProjectBreakpoints.clear(); + else + mBreakpoints.clear(); + if (forProject == mIsForProject) + endResetModel(); } -void BreakpointModel::removeBreakpoint(int row) +void BreakpointModel::removeBreakpoint(int row, bool forProject) { - beginRemoveRows(QModelIndex(),row,row); - mList.removeAt(row); - endRemoveRows(); + if (forProject==mIsForProject) + beginRemoveRows(QModelIndex(),row,row); + if (forProject) + mProjectBreakpoints.removeAt(row); + else + mBreakpoints.removeAt(row); + if (forProject==mIsForProject) + endRemoveRows(); } void BreakpointModel::invalidateAllBreakpointNumbers() { - foreach (PBreakpoint bp,mList) { + foreach (PBreakpoint bp,mBreakpoints) { + bp->number = -1; + } + foreach (PBreakpoint bp,mProjectBreakpoints) { bp->number = -1; } //emit dateChanged(createIndex(0,0),) } -PBreakpoint BreakpointModel::setBreakPointCondition(int index, const QString &condition) +PBreakpoint BreakpointModel::setBreakPointCondition(int index, const QString &condition,bool forProject) { - PBreakpoint breakpoint = mList[index]; + PBreakpoint breakpoint = breakpoints(forProject)[index]; breakpoint->condition = condition; - emit dataChanged(createIndex(index,0),createIndex(index,2)); + if (forProject==mIsForProject) + emit dataChanged(createIndex(index,0),createIndex(index,2)); return breakpoint; } -const QList &BreakpointModel::breakpoints() const +PBreakpoint BreakpointModel::breakpoint(int index, bool forProject) const { - return mList; -} - -PBreakpoint BreakpointModel::breakpoint(int index) const -{ - if (index<0 && index>=mList.count()) + const QList list=breakpoints(forProject); + if (index<0 && index>=list.count()) return PBreakpoint(); - return mList[index]; + return list[index]; } -void BreakpointModel::save(const QString &filename) -{ - QFile file(filename); - if (file.open(QFile::WriteOnly | QFile::Truncate)) { - QJsonArray array; - foreach (const PBreakpoint& breakpoint, mList) { - QJsonObject obj; - obj["filename"]=breakpoint->filename; - obj["line"]=breakpoint->line; - obj["condition"]=breakpoint->condition; - obj["enabled"]=breakpoint->enabled; - obj["breakpoint_type"] = static_cast(breakpoint->breakpointType); - array.append(obj); - } - QJsonDocument doc; - doc.setArray(array); - if (file.write(doc.toJson())<0) { - throw FileError(tr("Save file '%1' failed.") - .arg(filename)); - } - } else { - throw FileError(tr("Can't open file '%1' for write.") - .arg(filename)); - } -} - -void BreakpointModel::load(const QString &filename) -{ - clear(); - QFile file(filename); - if (!file.exists()) - return; - if (file.open(QFile::ReadOnly)) { - QByteArray content = file.readAll(); - QJsonParseError error; - QJsonDocument doc(QJsonDocument::fromJson(content,&error)); - if (error.error != QJsonParseError::NoError) { - throw FileError(tr("Error in json file '%1':%2 : %3") - .arg(filename) - .arg(error.offset) - .arg(error.errorString())); - } - QJsonArray array = doc.array(); - for (int i=0;i(); - breakpoint->filename = QFileInfo(obj["filename"].toString()).absoluteFilePath(); - breakpoint->line = obj["line"].toInt(); - breakpoint->condition = obj["condition"].toString(); - breakpoint->enabled = obj["enabled"].toBool(); - breakpoint->breakpointType = static_cast(obj["breakpoint_type"].toInt()); - - addBreakpoint(breakpoint); - } - } else { - throw FileError(tr("Can't open file '%1' for read.") - .arg(filename)); - } -} void BreakpointModel::updateBreakpointNumber(const QString& filename, int line, int number) { - foreach (PBreakpoint bp, mList) { + foreach (PBreakpoint bp, breakpoints(mIsForProject)) { if (bp->filename == filename && bp->line == line) { bp->number = number; return; @@ -1711,34 +1869,76 @@ void BreakpointModel::updateBreakpointNumber(const QString& filename, int line, } } -void BreakpointModel::onFileDeleteLines(const QString& filename, int startLine, int count) +void BreakpointModel::onFileDeleteLines(const QString& filename, int startLine, int count, bool forProject) { - for (int i = mList.count()-1;i>=0;i--){ - PBreakpoint breakpoint = mList[i]; + const QList &list=breakpoints(forProject); + for (int i = list.count()-1;i>=0;i--){ + PBreakpoint breakpoint = list[i]; if (breakpoint->filename == filename && breakpoint->line>=startLine) { if (breakpoint->line >= startLine+count) { breakpoint->line -= count; - emit dataChanged(createIndex(i,0),createIndex(i,2)); + if (forProject==mIsForProject) + emit dataChanged(createIndex(i,0),createIndex(i,2)); } else { - removeBreakpoint(i); + removeBreakpoint(i,forProject); } } } } -void BreakpointModel::onFileInsertLines(const QString& filename, int startLine, int count) +void BreakpointModel::onFileInsertLines(const QString& filename, int startLine, int count, bool forProject) { - for (int i = mList.count()-1;i>=0;i--){ - PBreakpoint breakpoint = mList[i]; + const QList &list=breakpoints(forProject); + for (int i = list.count()-1;i>=0;i--){ + PBreakpoint breakpoint = list[i]; if (breakpoint->filename == filename && breakpoint->line>=startLine) { breakpoint->line+=count; - emit dataChanged(createIndex(i,0),createIndex(i,2)); + if (forProject == mIsForProject) + emit dataChanged(createIndex(i,0),createIndex(i,2)); } } } +bool BreakpointModel::isForProject() const +{ + return mIsForProject; +} + +void BreakpointModel::setIsForProject(bool newIsForProject) +{ + if (mIsForProject!=newIsForProject) { + beginResetModel(); + mIsForProject = newIsForProject; + endResetModel(); + } +} + +QList BreakpointModel::loadJson(const QJsonArray& jsonArray, qint64 criteriaTime) +{ + QList result; + + for (int i=0;i criteriaTime) { + PBreakpoint breakpoint = std::make_shared(); + breakpoint->filename = QFileInfo(obj["filename"].toString()).absoluteFilePath(); + breakpoint->line = obj["line"].toInt(); + breakpoint->condition = obj["condition"].toString(); + breakpoint->enabled = obj["enabled"].toBool(); + breakpoint->breakpointType = static_cast(obj["breakpoint_type"].toInt()); + breakpoint->timestamp = timestamp; + result.append(breakpoint); + } + } + + return result; +} BacktraceModel::BacktraceModel(QObject *parent):QAbstractTableModel(parent) { @@ -1836,6 +2036,7 @@ PTrace BacktraceModel::backtrace(int index) const WatchModel::WatchModel(QObject *parent):QAbstractItemModel(parent) { mUpdateCount = 0; + mIsForProject = false; } QVariant WatchModel::data(const QModelIndex &index, int role) const @@ -1866,7 +2067,7 @@ QModelIndex WatchModel::index(int row, int column, const QModelIndex &parent) co PWatchVar pChild; if (!parent.isValid()) { parentItem = nullptr; - pChild = mWatchVars[row]; + pChild = watchVars(mIsForProject)[row]; } else { parentItem = static_cast(parent.internalPointer()); pChild = parentItem->children[row]; @@ -1877,7 +2078,7 @@ QModelIndex WatchModel::index(int row, int column, const QModelIndex &parent) co return QModelIndex(); } -static int getWatchIndex(WatchVar* var, const QList list) { +static int getWatchIndex(WatchVar* var, const QList &list) { for (int i=0;i(index.internalPointer()); - WatchVar* parentItem = childItem->parent; - + PWatchVar parentItem = childItem->parent.lock(); //parent is root if (parentItem == nullptr) { return QModelIndex(); } int row; - WatchVar* grandItem = parentItem->parent; + PWatchVar grandItem = parentItem->parent.lock(); if (grandItem == nullptr) { - row = getWatchIndex(parentItem,mWatchVars); + row = getWatchIndex(parentItem.get(), watchVars(mIsForProject)); } else { - row = getWatchIndex(parentItem,grandItem->children); + row = getWatchIndex(parentItem.get(), grandItem->children); } - return createIndex(row,0,parentItem); + return createIndex(row,0,parentItem.get()); } int WatchModel::rowCount(const QModelIndex &parent) const { if (!parent.isValid()) { - return mWatchVars.count(); + return watchVars(mIsForProject).count(); } else { WatchVar* parentItem = static_cast(parent.internalPointer()); return parentItem->children.count(); @@ -1926,28 +2126,42 @@ int WatchModel::columnCount(const QModelIndex&) const void WatchModel::addWatchVar(PWatchVar watchVar) { - for (PWatchVar var:mWatchVars) { + QList &vars=(mIsForProject?mProjectWatchVars:mWatchVars); + for (PWatchVar var:vars) { if (watchVar->expression == var->expression) { return; } } - beginInsertRows(QModelIndex(),mWatchVars.count(),mWatchVars.count()); - mWatchVars.append(watchVar); + beginInsertRows(QModelIndex(),vars.count(),vars.count()); + vars.append(watchVar); endInsertRows(); } +void WatchModel::setWatchVars(const QList list, bool forProject) +{ + if (mIsForProject == forProject) + beginResetModel(); + if (forProject) { + mProjectWatchVars = list; + } else { + mWatchVars = list; + } + if (mIsForProject == forProject) + endResetModel(); +} + void WatchModel::removeWatchVar(const QString &express) { - for (int i=mWatchVars.size()-1;i>=0;i--) { - PWatchVar var = mWatchVars[i]; + QList &vars=(mIsForProject?mProjectWatchVars:mWatchVars); + for (int i=vars.size()-1;i>=0;i--) { + PWatchVar var = vars[i]; if (express == var->expression) { - this->beginResetModel(); - //this->beginRemoveRows(QModelIndex(),i,i); + QModelIndex parentIndex = index(var->parent.lock()); + beginRemoveRows(parentIndex,i,i); if (mVarIndex.contains(var->name)) mVarIndex.remove(var->name); - mWatchVars.removeAt(i); - //this->endRemoveRows(); - this->endResetModel(); + vars.removeAt(i); + endRemoveRows(); } } } @@ -1955,24 +2169,26 @@ void WatchModel::removeWatchVar(const QString &express) void WatchModel::removeWatchVar(const QModelIndex &index) { int r=index.row(); - this->beginRemoveRows(QModelIndex(),r,r); - PWatchVar var = mWatchVars[r]; + beginRemoveRows(QModelIndex(),r,r); + QList &vars=(mIsForProject?mProjectWatchVars:mWatchVars); + PWatchVar var = vars[r]; if (mVarIndex.contains(var->name)) mVarIndex.remove(var->name); - mWatchVars.removeAt(r); - this->endRemoveRows(); + vars.removeAt(r); + endRemoveRows(); } void WatchModel::clear() { - this->beginResetModel(); - mWatchVars.clear(); - this->endResetModel(); + beginResetModel(); + QList &vars=(mIsForProject?mProjectWatchVars:mWatchVars); + vars.clear(); + endResetModel(); } -const QList &WatchModel::watchVars() +const QList &WatchModel::watchVars() const { - return mWatchVars; + return watchVars(mIsForProject); } PWatchVar WatchModel::findWatchVar(const QModelIndex &index) @@ -1980,12 +2196,12 @@ PWatchVar WatchModel::findWatchVar(const QModelIndex &index) if (!index.isValid()) return PWatchVar(); int r=index.row(); - return mWatchVars[r]; + return watchVars(mIsForProject)[r]; } PWatchVar WatchModel::findWatchVar(const QString &expr) { - for (PWatchVar var:mWatchVars) { + foreach (const PWatchVar &var, watchVars(mIsForProject)) { if (expr == var->expression) { return var; } @@ -1996,7 +2212,7 @@ PWatchVar WatchModel::findWatchVar(const QString &expr) void WatchModel::resetAllVarInfos() { beginResetModel(); - foreach (PWatchVar var, mWatchVars) { + foreach (PWatchVar var, watchVars(mIsForProject)) { var->name.clear(); var->value = tr("Not Valid"); var->numChild = 0; @@ -2054,7 +2270,8 @@ void WatchModel::addVarChild(const QString &parentName, const QString &name, child->value = value; child->type = type; child->hasMore = hasMore; - child->parent = var.get(); + child->parent = var; + child->timestamp = QDateTime::currentMSecsSinceEpoch(); var->children.append(child); endInsertRows(); mVarIndex.insert(name,child); @@ -2096,10 +2313,30 @@ void WatchModel::updateAllHasMoreVars() } } +bool WatchModel::isForProject() const +{ + return mIsForProject; +} + +void WatchModel::setIsForProject(bool newIsForProject) +{ + if (newIsForProject!=mIsForProject) { + beginResetModel(); + mVarIndex.clear(); + mIsForProject=newIsForProject; + endResetModel(); + } +} + +const QList &WatchModel::watchVars(bool forProject) const +{ + return forProject?mProjectWatchVars:mWatchVars; +} + void WatchModel::clearAllVarInfos() { beginResetModel(); - foreach (PWatchVar var, mWatchVars) { + foreach (PWatchVar var, watchVars(mIsForProject)) { var->name.clear(); var->value = tr("Execute to evaluate"); var->numChild = 0; @@ -2132,10 +2369,11 @@ void WatchModel::notifyUpdated(PWatchVar var) if (!var) return; int row; - if (var->parent==nullptr) { - row = mWatchVars.indexOf(var); + PWatchVar parent = var->parent.lock(); + if (parent==nullptr) { + row = watchVars(mIsForProject).indexOf(var); } else { - row = var->parent->children.indexOf(var); + row = parent->children.indexOf(var); } if (row<0) return; @@ -2143,62 +2381,16 @@ void WatchModel::notifyUpdated(PWatchVar var) emit dataChanged(createIndex(row,0,var.get()),createIndex(row,0,var.get())); } -void WatchModel::save(const QString &filename) +QJsonArray WatchModel::toJson(bool forProject) { - QFile file(filename); - if (file.open(QFile::WriteOnly | QFile::Truncate)) { - QJsonArray array; - foreach (const PWatchVar& watchVar, mWatchVars) { - QJsonObject obj; - obj["expression"]=watchVar->expression; - array.append(obj); - } - QJsonDocument doc; - doc.setArray(array); - if (file.write(doc.toJson())<0) { - throw FileError(tr("Save file '%1' failed.") - .arg(filename)); - } - } else { - throw FileError(tr("Can't open file '%1' for write.") - .arg(filename)); - } -} - -void WatchModel::load(const QString &filename) -{ - clear(); - QFile file(filename); - if (!file.exists()) - return; - if (file.open(QFile::ReadOnly)) { - QByteArray content = file.readAll(); - QJsonParseError error; - QJsonDocument doc(QJsonDocument::fromJson(content,&error)); - if (error.error != QJsonParseError::NoError) { - throw FileError(tr("Error in json file '%1':%2 : %3") - .arg(filename) - .arg(error.offset) - .arg(error.errorString())); - } - QJsonArray array = doc.array(); - for (int i=0;i(); - var->parent= nullptr; - var->expression = obj["expression"].toString(); - var->value = tr("Execute to evaluate"); - var->numChild = 0; - var->hasMore=false; - var->parent = nullptr; - - addWatchVar(var); - } - } else { - throw FileError(tr("Can't open file '%1' for read.") - .arg(filename)); + QJsonArray array; + foreach (const PWatchVar& watchVar, watchVars(forProject)) { + QJsonObject obj; + obj["expression"]=watchVar->expression; + obj["timestamp"]=QString("%1").arg(watchVar->timestamp); + array.append(obj); } + return array; } QModelIndex WatchModel::index(PWatchVar var) const @@ -2211,10 +2403,11 @@ QModelIndex WatchModel::index(PWatchVar var) const QModelIndex WatchModel::index(WatchVar* pVar) const { if (pVar==nullptr) return QModelIndex(); - if (pVar->parent) { + PWatchVar parent=pVar->parent.lock(); + if (parent) { int row=-1; - for (int i=0;iparent->children.count();i++) { - if (pVar->parent->children[i].get() == pVar) { + for (int i=0;ichildren.count();i++) { + if (parent->children[i].get() == pVar) { row = i; break; } @@ -2223,9 +2416,10 @@ QModelIndex WatchModel::index(WatchVar* pVar) const { return QModelIndex(); return createIndex(row,0,pVar); } else { + const QList &vars=watchVars(mIsForProject); int row=-1; - for (int i=0;i WatchModel::loadJson(const QJsonArray &jsonArray, qint64 criteriaTimestamp) +{ + + QList result; + QJsonArray array = jsonArray; + for (int i=0;icriteriaTimestamp) { + PWatchVar var = std::make_shared(); + var->parent= PWatchVar(); + var->expression = obj["expression"].toString(); + var->value = tr("Execute to evaluate"); + var->numChild = 0; + var->hasMore=false; + var->timestamp = timestamp; + result.append(var); + } + } + return result; +} + bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) { diff --git a/RedPandaIDE/debugger.h b/RedPandaIDE/debugger.h index dd40d4f2..7be7344c 100644 --- a/RedPandaIDE/debugger.h +++ b/RedPandaIDE/debugger.h @@ -56,7 +56,8 @@ struct WatchVar { QString type; int numChild; QList children; - WatchVar * parent; //use raw point to prevent circular-reference + std::weak_ptr parent; //use raw point to prevent circular-reference + qint64 timestamp; }; enum class BreakpointType { @@ -75,10 +76,20 @@ struct Breakpoint { QString condition; bool enabled; BreakpointType breakpointType; + qint64 timestamp; }; using PBreakpoint = std::shared_ptr; +struct DebugConfig { + QList breakpoints; + QList watchVars; + qint64 timestamp; +}; + + +using PDebugConfig=std::shared_ptr; + struct Trace { QString funcname; QString filename; @@ -105,6 +116,8 @@ private: QHash mRegisterValues; }; +class Debugger; + class BreakpointModel: public QAbstractTableModel { Q_OBJECT // QAbstractItemModel interface @@ -114,21 +127,34 @@ public: int columnCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - void addBreakpoint(PBreakpoint p); - void clear(); - void removeBreakpoint(int index); - PBreakpoint setBreakPointCondition(int index, const QString& condition); - const QList& breakpoints() const; - PBreakpoint breakpoint(int index) const; - void save(const QString& filename); - void load(const QString& filename); + void addBreakpoint(PBreakpoint p, bool forProject); + void clear(bool forProject); + void removeBreakpoint(int index, bool forProject); + PBreakpoint setBreakPointCondition(int index, const QString& condition, bool forProject); + const QList& breakpoints(bool forProject) const { + return forProject?mProjectBreakpoints:mBreakpoints; + } + + PBreakpoint breakpoint(int index, bool forProject) const; + public slots: void updateBreakpointNumber(const QString& filename, int line, int number); void invalidateAllBreakpointNumbers(); // call this when gdb is stopped - void onFileDeleteLines(const QString& filename, int startLine, int count); - void onFileInsertLines(const QString& filename, int startLine, int count); + void onFileDeleteLines(const QString& filename, int startLine, int count, bool forProject); + void onFileInsertLines(const QString& filename, int startLine, int count, bool forProject); private: - QList mList; + bool isForProject() const; + void setIsForProject(bool newIsForProject); + QList loadJson(const QJsonArray& jsonArray, qint64 criteriaTime); + QJsonArray toJson(const QString& projectFolder); + void setBreakpoints(const QList& list, bool forProject); + +private: + QList mBreakpoints; + QList mProjectBreakpoints; + bool mIsForProject; + + friend class Debugger; }; class BacktraceModel : public QAbstractTableModel { @@ -164,11 +190,12 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; bool hasChildren(const QModelIndex &parent) const override; - void addWatchVar(PWatchVar watchVar); + QModelIndex index(PWatchVar var) const; + QModelIndex index(WatchVar* pVar) const; + void removeWatchVar(const QString& expression); void removeWatchVar(const QModelIndex& index); void clear(); - const QList& watchVars(); PWatchVar findWatchVar(const QModelIndex& index); PWatchVar findWatchVar(const QString& expr); void resetAllVarInfos(); @@ -176,8 +203,6 @@ public: void beginUpdate(); void endUpdate(); void notifyUpdated(PWatchVar var); - void save(const QString& filename); - void load(const QString& filename); signals: void setWatchVarValue(const QString& name, const QString& value); public slots: @@ -200,17 +225,30 @@ public slots: signals: void fetchChildren(const QString& name); private: - QModelIndex index(PWatchVar var) const; - QModelIndex index(WatchVar* pVar) const; + bool isForProject() const; + void setIsForProject(bool newIsForProject); + const QList &watchVars(bool forProject) const; + QJsonArray toJson(bool forProject); + QList loadJson(const QJsonArray &jsonArray, qint64 criteriaTimestamp); + const QList &watchVars() const; + void addWatchVar(PWatchVar watchVar); + void setWatchVars(const QList list, bool forProject); + private: QList mWatchVars; - QHash mVarIndex; + QList mProjectWatchVars; + + QHash mVarIndex; //var index is only valid for the current debugging session + int mUpdateCount; + bool mIsForProject; // QAbstractItemModel interface public: bool setData(const QModelIndex &index, const QVariant &value, int role) override; Qt::ItemFlags flags(const QModelIndex &index) const override; + + friend class Debugger; }; struct MemoryLine { @@ -267,20 +305,29 @@ public: bool inferiorRunning(); void interrupt(); + bool isForProject() const; + void setIsForProject(bool newIsForProject); + //breakpoints void addBreakpoint(int line, const Editor* editor); - void addBreakpoint(int line, const QString& filename); - void deleteBreakpoints(const QString& filename); + void addBreakpoint(int line, const QString& filename, bool forProject); + void deleteBreakpoints(const QString& filename, bool forProject); void deleteBreakpoints(const Editor* editor); - void deleteBreakpoints(); + void deleteBreakpoints(bool forProject); void removeBreakpoint(int line, const Editor* editor); - void removeBreakpoint(int line, const QString& filename); - void removeBreakpoint(int index); - PBreakpoint breakpointAt(int line, const QString& filename, int &index); - PBreakpoint breakpointAt(int line, const Editor* editor, int &index); - void setBreakPointCondition(int index, const QString& condition); + void removeBreakpoint(int line, const QString& filename, bool forProject); + void removeBreakpoint(int index, bool forProject); + PBreakpoint breakpointAt(int line, const QString &filename, int *index, bool forProject); + PBreakpoint breakpointAt(int line, const Editor *editor, int *index); + void setBreakPointCondition(int index, const QString& condition, bool forProject); void sendAllBreakpointsToDebugger(); + void saveForNonproject(const QString &filename); + void saveForProject(const QString &filename, const QString &projectFolder); + + void loadForNonproject(const QString &filename); + void loadForProject(const QString& filename, const QString& projectFolder); + //watch vars void addWatchVar(const QString& expression); void modifyWatchVarExpression(const QString& oldExpr, const QString& newExpr); @@ -292,18 +339,18 @@ public: PWatchVar watchVarAt(const QModelIndex& index); // void notifyWatchVarUpdated(PWatchVar var); - BacktraceModel* backtraceModel(); - BreakpointModel* breakpointModel(); + std::shared_ptr backtraceModel(); + std::shared_ptr breakpointModel(); bool executing() const; int leftPageIndexBackup() const; void setLeftPageIndexBackup(int leftPageIndexBackup); - WatchModel *watchModel() const; + std::shared_ptr watchModel() const; - RegisterModel *registerModel() const; + std::shared_ptr registerModel() const; - MemoryModel *memoryModel() const; + std::shared_ptr memoryModel() const; bool forceUTF8() const; void setForceUTF8(bool newForceUTF8); @@ -320,8 +367,10 @@ private: void sendWatchCommand(PWatchVar var); void sendRemoveWatchCommand(PWatchVar var); void sendBreakpointCommand(PBreakpoint breakpoint); - void sendClearBreakpointCommand(int index); + void sendClearBreakpointCommand(int index, bool forProject); void sendClearBreakpointCommand(PBreakpoint breakpoint); + void save(const QString& filename, const QString& projectFolder); + PDebugConfig load(const QString& filename, bool forProject); private slots: void syncFinishedParsing(); @@ -339,15 +388,17 @@ private slots: private: bool mExecuting; bool mCommandChanged; - BreakpointModel *mBreakpointModel; - BacktraceModel *mBacktraceModel; - WatchModel *mWatchModel; - RegisterModel *mRegisterModel; - MemoryModel *mMemoryModel; + std::shared_ptr mBreakpointModel; + std::shared_ptr mBacktraceModel; + std::shared_ptr mWatchModel; + std::shared_ptr mRegisterModel; + std::shared_ptr mMemoryModel; DebugReader *mReader; DebugTarget *mTarget; bool mForceUTF8; int mLeftPageIndexBackup; + qint64 mLastLoadtime; + qint64 mProjectLastLoadtime; }; class DebugTarget: public QThread { diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index eaab8128..aed3db26 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -1291,7 +1291,7 @@ void Editor::showEvent(QShowEvent */*event*/) resetCppParser(mParser); reparse(); } - + pMainWindow->debugger()->setIsForProject(inProject()); pMainWindow->bookmarkModel()->setIsForProject(inProject()); // if (pSettings->codeCompletion().clearWhenEditorHidden() // && !inProject()) { @@ -1696,7 +1696,7 @@ void Editor::onTipEvalValueReady(const QString& value) void Editor::onLinesDeleted(int first, int count) { pMainWindow->caretList().linesDeleted(this,first,count); - pMainWindow->debugger()->breakpointModel()->onFileDeleteLines(mFilename,first,count); + pMainWindow->debugger()->breakpointModel()->onFileDeleteLines(mFilename,first,count,inProject()); pMainWindow->bookmarkModel()->onFileDeleteLines(mFilename,first,count, inProject()); resetBreakpoints(); resetBookmarks(); @@ -1708,7 +1708,7 @@ void Editor::onLinesDeleted(int first, int count) void Editor::onLinesInserted(int first, int count) { pMainWindow->caretList().linesInserted(this,first,count); - pMainWindow->debugger()->breakpointModel()->onFileInsertLines(mFilename,first,count); + pMainWindow->debugger()->breakpointModel()->onFileInsertLines(mFilename,first,count, inProject()); pMainWindow->bookmarkModel()->onFileInsertLines(mFilename,first,count, inProject()); resetBreakpoints(); resetBookmarks(); @@ -1756,7 +1756,7 @@ void Editor::resetBreakpoints() { mBreakpointLines.clear(); foreach (const PBreakpoint& breakpoint, - pMainWindow->debugger()->breakpointModel()->breakpoints()) { + pMainWindow->debugger()->breakpointModel()->breakpoints(inProject())) { if (breakpoint->filename == mFilename) { mBreakpointLines.insert(breakpoint->line); } @@ -4444,7 +4444,7 @@ void Editor::removeBreakpointFocus() void Editor::modifyBreakpointProperty(int line) { int index; - PBreakpoint breakpoint = pMainWindow->debugger()->breakpointAt(line,this,index); + PBreakpoint breakpoint = pMainWindow->debugger()->breakpointAt(line,this,&index); if (!breakpoint) return; bool isOk; @@ -4454,7 +4454,7 @@ void Editor::modifyBreakpointProperty(int line) QLineEdit::Normal, breakpoint->condition,&isOk); if (isOk) { - pMainWindow->debugger()->setBreakPointCondition(index,s); + pMainWindow->debugger()->setBreakPointCondition(index,s,inProject()); } } diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index cc18691b..aa780e0c 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -163,34 +163,26 @@ MainWindow::MainWindow(QWidget *parent) mDebugger = std::make_shared(); m=ui->tblBreakpoints->selectionModel(); - ui->tblBreakpoints->setModel(mDebugger->breakpointModel()); + ui->tblBreakpoints->setModel(mDebugger->breakpointModel().get()); delete m; m=ui->tblStackTrace->selectionModel(); - ui->tblStackTrace->setModel(mDebugger->backtraceModel()); + ui->tblStackTrace->setModel(mDebugger->backtraceModel().get()); delete m; m=ui->watchView->selectionModel(); - ui->watchView->setModel(mDebugger->watchModel()); + ui->watchView->setModel(mDebugger->watchModel().get()); delete m; m=ui->tblMemoryView->selectionModel(); - ui->tblMemoryView->setModel(mDebugger->memoryModel()); + ui->tblMemoryView->setModel(mDebugger->memoryModel().get()); delete m; ui->tblMemoryView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); try { - mDebugger->breakpointModel()->load(includeTrailingPathDelimiter(pSettings->dirs().config()) - +DEV_BREAKPOINTS_FILE); - } catch (FileError &e) { - QMessageBox::warning(nullptr, - tr("Error"), - e.reason()); - } - try { - mDebugger->watchModel()->load(includeTrailingPathDelimiter(pSettings->dirs().config()) - +DEV_WATCH_FILE); + mDebugger->loadForNonproject(includeTrailingPathDelimiter(pSettings->dirs().config()) + +DEV_DEBUGGER_FILE); } catch (FileError &e) { QMessageBox::warning(nullptr, tr("Error"), @@ -1311,6 +1303,10 @@ void MainWindow::openProject(const QString &filename, bool openFiles) mBookmarkModel->loadProjectBookmarks( changeFileExt(mProject->filename(), PROJECT_BOOKMARKS_EXT), mProject->directory()); + mDebugger->setIsForProject(true); + mDebugger->loadForProject( + changeFileExt(mProject->filename(), PROJECT_DEBUG_EXT), + mProject->directory()); if (openFiles) { PProjectUnit unit = mProject->doAutoOpen(); @@ -4068,21 +4064,21 @@ void MainWindow::onBreakpointRemove() { int index =ui->tblBreakpoints->selectionModel()->currentIndex().row(); - PBreakpoint breakpoint = debugger()->breakpointModel()->breakpoint(index); + PBreakpoint breakpoint = debugger()->breakpointModel()->breakpoint(index, debugger()->isForProject()); if (breakpoint) { Editor * e = mEditorList->getOpenedEditorByFilename(breakpoint->filename); if (e) { if (e->hasBreakpoint(breakpoint->line)) e->toggleBreakpoint(breakpoint->line); } else { - debugger()->breakpointModel()->removeBreakpoint(index); + debugger()->breakpointModel()->removeBreakpoint(index,debugger()->isForProject()); } } } void MainWindow::onBreakpointViewRemoveAll() { - pMainWindow->debugger()->deleteBreakpoints(); + debugger()->deleteBreakpoints(debugger()->isForProject()); for (int i=0;ipageCount();i++) { Editor * e = (*(mEditorList))[i]; if (e) { @@ -4096,7 +4092,8 @@ void MainWindow::onBreakpointViewProperty() int index =ui->tblBreakpoints->selectionModel()->currentIndex().row(); PBreakpoint breakpoint = debugger()->breakpointModel()->breakpoint( - index + index, + debugger()->isForProject() ); if (breakpoint) { bool isOk; @@ -4106,7 +4103,7 @@ void MainWindow::onBreakpointViewProperty() QLineEdit::Normal, breakpoint->condition,&isOk); if (isOk) { - pMainWindow->debugger()->setBreakPointCondition(index,s); + pMainWindow->debugger()->setBreakPointCondition(index,s,debugger()->isForProject()); } } } @@ -4373,6 +4370,10 @@ void MainWindow::closeProject(bool refreshEditor) changeFileExt(mProject->filename(), PROJECT_BOOKMARKS_EXT), mProject->directory()); + mDebugger->saveForProject( + changeFileExt(mProject->filename(), PROJECT_DEBUG_EXT), + mProject->directory()); + mClassBrowserModel.beginUpdate(); // Remember it pSettings->history().addToOpenedProjects(mProject->filename()); @@ -4394,6 +4395,7 @@ void MainWindow::closeProject(bool refreshEditor) if (!mQuitting) { mBookmarkModel->setIsForProject(false); + mDebugger->setIsForProject(false); // Clear error browser clearIssues(); updateProjectView(); @@ -4610,10 +4612,10 @@ void MainWindow::closeEvent(QCloseEvent *event) { e.reason()); } - if (pSettings->debugger().autosaveBreakpoints()) { + if (pSettings->debugger().autosave()) { try { - mDebugger->breakpointModel()->save(includeTrailingPathDelimiter(pSettings->dirs().config()) - +DEV_BREAKPOINTS_FILE); + mDebugger->saveForNonproject(includeTrailingPathDelimiter(pSettings->dirs().config()) + +DEV_DEBUGGER_FILE); } catch (FileError& e) { QMessageBox::warning(nullptr, tr("Save Error"), @@ -4621,20 +4623,7 @@ void MainWindow::closeEvent(QCloseEvent *event) { } } else removeFile(includeTrailingPathDelimiter(pSettings->dirs().config()) - +DEV_BREAKPOINTS_FILE); - if (pSettings->debugger().autosaveWatches()) { - try { - mDebugger->watchModel()->save(includeTrailingPathDelimiter(pSettings->dirs().config()) - +DEV_WATCH_FILE); - } catch (FileError& e) { - QMessageBox::warning(nullptr, - tr("Save Error"), - e.reason()); - } - } else - removeFile(includeTrailingPathDelimiter(pSettings->dirs().config()) - +DEV_WATCH_FILE); - + +DEV_DEBUGGER_FILE); } if (!mShouldRemoveAllSettings && pSettings->editor().autoLoadLastFiles()) { @@ -5289,20 +5278,21 @@ bool MainWindow::debugInferiorhasBreakpoint() Editor * e = mEditorList->getEditor(); if (e==nullptr) return false; - if (!e->inProject()) { - for (const PBreakpoint& breakpoint:mDebugger->breakpointModel()->breakpoints()) { - if (e->filename() == breakpoint->filename) { - return true; - } - } - } else { - for (const PBreakpoint& breakpoint:mDebugger->breakpointModel()->breakpoints()) { - Editor* e1 = mEditorList->getOpenedEditorByFilename(breakpoint->filename); - if (e1 && e1->inProject()) { - return true; - } + for (const PBreakpoint& breakpoint:mDebugger->breakpointModel()->breakpoints(e->inProject())) { + if (e->filename() == breakpoint->filename) { + return true; } } +// if (!e->inProject()) { + +// } else { +// for (const PBreakpoint& breakpoint:mDebugger->breakpointModel()->breakpoints(e->inProject())) { +// Editor* e1 = mEditorList->getOpenedEditorByFilename(breakpoint->filename); +// if (e1 && e1->inProject()) { +// return true; +// } +// } +// } return false; } @@ -5875,7 +5865,9 @@ void MainWindow::on_tblStackTrace_doubleClicked(const QModelIndex &index) void MainWindow::on_tblBreakpoints_doubleClicked(const QModelIndex &index) { - PBreakpoint breakpoint = mDebugger->breakpointModel()->breakpoint(index.row()); + PBreakpoint breakpoint = mDebugger->breakpointModel()->breakpoint( + index.row(), + mDebugger->isForProject()); if (breakpoint) { Editor * e = mEditorList->getEditorByFilename(breakpoint->filename); if (e) { diff --git a/RedPandaIDE/settings.cpp b/RedPandaIDE/settings.cpp index cf081034..818bdfb3 100644 --- a/RedPandaIDE/settings.cpp +++ b/RedPandaIDE/settings.cpp @@ -3532,16 +3532,6 @@ void Settings::Debugger::setSkipCustomLibraries(bool newSkipCustomLibraries) mSkipCustomLibraries = newSkipCustomLibraries; } -bool Settings::Debugger::autosaveWatches() const -{ - return mAutosaveWatches; -} - -void Settings::Debugger::setAutosaveWatches(bool newAutosaveWatches) -{ - mAutosaveWatches = newAutosaveWatches; -} - bool Settings::Debugger::openCPUInfoWhenSignaled() const { return mOpenCPUInfoWhenSignaled; @@ -3592,14 +3582,14 @@ void Settings::Debugger::setMemoryViewColumns(int newMemoryViewColumns) mMemoryViewColumns = newMemoryViewColumns; } -bool Settings::Debugger::autosaveBreakpoints() const +bool Settings::Debugger::autosave() const { - return mAutosaveBreakpoints; + return mAutosave; } -void Settings::Debugger::setAutosaveBreakpoints(bool newAutosaveBreakpoints) +void Settings::Debugger::setAutosave(bool newAutosave) { - mAutosaveBreakpoints = newAutosaveBreakpoints; + mAutosave = newAutosave; } bool Settings::Debugger::useIntelStyle() const @@ -3644,8 +3634,7 @@ void Settings::Debugger::doSave() saveValue("skip_system_lib", mSkipSystemLibraries); saveValue("skip_project_lib", mSkipProjectLibraries); saveValue("skip_custom_lib", mSkipCustomLibraries); - saveValue("autosave_breakpoints",mAutosaveBreakpoints); - saveValue("autosave_watches",mAutosaveWatches); + saveValue("autosave",mAutosave); saveValue("open_cpu_info_when_signaled",mOpenCPUInfoWhenSignaled); saveValue("use_gdb_server", mUseGDBServer); saveValue("gdb_server_port",mGDBServerPort); @@ -3670,8 +3659,7 @@ void Settings::Debugger::doLoad() mSkipSystemLibraries = boolValue("skip_system_lib",true); mSkipProjectLibraries = boolValue("skip_project_lib",true); mSkipCustomLibraries = boolValue("skip_custom_lib",false); - mAutosaveBreakpoints = boolValue("autosave_breakpoints",true); - mAutosaveWatches = boolValue("autosave_watches",true); + mAutosave = boolValue("autosave",true); mOpenCPUInfoWhenSignaled = boolValue("open_cpu_info_when_signaled",true); #ifdef Q_OS_WIN mUseGDBServer = boolValue("use_gdb_server", false); diff --git a/RedPandaIDE/settings.h b/RedPandaIDE/settings.h index 241b65c0..e71749dd 100644 --- a/RedPandaIDE/settings.h +++ b/RedPandaIDE/settings.h @@ -1126,12 +1126,6 @@ public: bool skipCustomLibraries() const; void setSkipCustomLibraries(bool newSkipCustomLibraries); - bool autosaveBreakpoints() const; - void setAutosaveBreakpoints(bool newAutosaveBreakpoints); - - bool autosaveWatches() const; - void setAutosaveWatches(bool newAutosaveWatches); - bool openCPUInfoWhenSignaled() const; void setOpenCPUInfoWhenSignaled(bool newOpenCPUInfoWhenSignaled); @@ -1146,6 +1140,9 @@ public: int memoryViewColumns() const; void setMemoryViewColumns(int newMemoryViewColumns); + bool autosave() const; + void setAutosave(bool newAutosave); + private: bool mEnableDebugConsole; bool mShowDetailLog; @@ -1157,8 +1154,7 @@ public: bool mSkipSystemLibraries; bool mSkipProjectLibraries; bool mSkipCustomLibraries; - bool mAutosaveBreakpoints; - bool mAutosaveWatches; + bool mAutosave; bool mOpenCPUInfoWhenSignaled; bool mUseGDBServer; int mGDBServerPort; diff --git a/RedPandaIDE/settingsdialog/debuggeneralwidget.cpp b/RedPandaIDE/settingsdialog/debuggeneralwidget.cpp index 427647de..6f91da9f 100644 --- a/RedPandaIDE/settingsdialog/debuggeneralwidget.cpp +++ b/RedPandaIDE/settingsdialog/debuggeneralwidget.cpp @@ -48,8 +48,7 @@ void DebugGeneralWidget::doLoad() ui->chkSkipSystemLib->setChecked(pSettings->debugger().skipSystemLibraries()); ui->chkSkipProjectLib->setChecked(pSettings->debugger().skipProjectLibraries()); ui->chkSkipCustomLib->setChecked(pSettings->debugger().skipCustomLibraries()); - ui->chkAutosaveBreakpoints->setChecked(pSettings->debugger().autosaveBreakpoints()); - ui->chkAutosaveWatches->setChecked(pSettings->debugger().autosaveWatches()); + ui->chkAutosave->setChecked(pSettings->debugger().autosave()); #ifdef Q_OS_WIN ui->grpUseGDBServer->setCheckable(true); ui->grpUseGDBServer->setChecked(pSettings->debugger().useGDBServer()); @@ -72,8 +71,7 @@ void DebugGeneralWidget::doSave() pSettings->debugger().setSkipSystemLibraries(ui->chkSkipSystemLib->isChecked()); pSettings->debugger().setSkipProjectLibraries(ui->chkSkipProjectLib->isChecked()); pSettings->debugger().setSkipCustomLibraries(ui->chkSkipCustomLib->isChecked()); - pSettings->debugger().setAutosaveBreakpoints(ui->chkAutosaveBreakpoints->isChecked()); - pSettings->debugger().setAutosaveWatches(ui->chkAutosaveWatches->isChecked()); + pSettings->debugger().setAutosave(ui->chkAutosave->isChecked()); #ifdef Q_OS_WIN pSettings->debugger().setUseGDBServer(ui->grpUseGDBServer->isChecked()); #endif diff --git a/RedPandaIDE/settingsdialog/debuggeneralwidget.ui b/RedPandaIDE/settingsdialog/debuggeneralwidget.ui index 3d157511..f298c2f9 100644 --- a/RedPandaIDE/settingsdialog/debuggeneralwidget.ui +++ b/RedPandaIDE/settingsdialog/debuggeneralwidget.ui @@ -318,16 +318,9 @@ - + - Autosave breakpoints - - - - - - - Autosave watches + Autosave breakpoints and watches diff --git a/RedPandaIDE/systemconsts.h b/RedPandaIDE/systemconsts.h index 274aaf44..1f7e997b 100644 --- a/RedPandaIDE/systemconsts.h +++ b/RedPandaIDE/systemconsts.h @@ -71,6 +71,7 @@ #define DEV_PROJECT_EXT "dev" #define PROJECT_BOOKMARKS_EXT "bookmarks" +#define PROJECT_DEBUG_EXT "debug" #define RC_EXT "rc" #define RES_EXT "res" #define H_EXT "h" @@ -89,8 +90,7 @@ #define DEV_SHORTCUT_FILE "shortcuts.json" #define DEV_TOOLS_FILE "tools.json" #define DEV_BOOKMARK_FILE "bookmarks.json" -#define DEV_BREAKPOINTS_FILE "breakpoints.json" -#define DEV_WATCH_FILE "watch.json" +#define DEV_DEBUGGER_FILE "debugger.json" #ifdef Q_OS_WIN # define PATH_SENSITIVITY Qt::CaseInsensitive diff --git a/RedPandaIDE/widgets/bookmarkmodel.cpp b/RedPandaIDE/widgets/bookmarkmodel.cpp index 5f4fba39..9ef03fc9 100644 --- a/RedPandaIDE/widgets/bookmarkmodel.cpp +++ b/RedPandaIDE/widgets/bookmarkmodel.cpp @@ -182,7 +182,9 @@ void BookmarkModel::loadBookmarks(const QString &filename) { if (!mIsForProject) beginResetModel(); - mBookmarks = load(filename,0,&mLastLoadBookmarksTimestamp); + qint64 t; + mLastLoadBookmarksTimestamp = QDateTime::currentMSecsSinceEpoch(); + mBookmarks = load(filename,0,&t); if (!mIsForProject) endResetModel(); } @@ -227,7 +229,6 @@ void BookmarkModel::save(const QString &filename, const QString& projectFolder) if (pTemp->timestamp<=bookmark->timestamp) compareHash.insert(key,bookmark); } - compareHash.insert(key,bookmark); } QList saveList; foreach (const PBookmark& bookmark, compareHash) { @@ -320,7 +321,9 @@ void BookmarkModel::loadProjectBookmarks(const QString &filename, const QString& { if (mIsForProject) beginResetModel(); - mProjectBookmarks = load(filename,0,&mLastLoadProjectBookmarksTimestamp); + qint64 t; + mLastLoadProjectBookmarksTimestamp = QDateTime::currentMSecsSinceEpoch(); + mProjectBookmarks = load(filename,0,&t); QDir folder(projectFolder); foreach (PBookmark bookmark, mProjectBookmarks) { bookmark->filename=folder.absoluteFilePath(bookmark->filename); diff --git a/RedPandaIDE/widgets/cpudialog.cpp b/RedPandaIDE/widgets/cpudialog.cpp index 7fa90904..0ee12877 100644 --- a/RedPandaIDE/widgets/cpudialog.cpp +++ b/RedPandaIDE/widgets/cpudialog.cpp @@ -56,7 +56,7 @@ CPUDialog::CPUDialog(QWidget *parent) : } resetEditorFont(screenDPI()); QItemSelectionModel *m=ui->lstRegister->selectionModel(); - ui->lstRegister->setModel(pMainWindow->debugger()->registerModel()); + ui->lstRegister->setModel(pMainWindow->debugger()->registerModel().get()); delete m; ui->rdIntel->setChecked(pSettings->debugger().useIntelStyle());