From 975d90c8f1473d2e2a947df0d36c1862251b0740 Mon Sep 17 00:00:00 2001 From: Roy Qu Date: Tue, 11 Oct 2022 21:51:33 +0800 Subject: [PATCH] - enhancement: save project's bookmark in it's own bookmark file - enhancement: project and non-project files use different bookmark view (auto switch when switch editors) - enhancement: auto merge when save bookmarks. --- NEWS.md | 4 +- RedPandaIDE/editor.cpp | 12 +- RedPandaIDE/editor.h | 4 +- RedPandaIDE/mainwindow.cpp | 148 ++++++----- RedPandaIDE/mainwindow.h | 1 + RedPandaIDE/mainwindow.ui | 5 +- RedPandaIDE/systemconsts.h | 1 + RedPandaIDE/widgets/bookmarkmodel.cpp | 366 ++++++++++++++++++++++---- RedPandaIDE/widgets/bookmarkmodel.h | 40 ++- 9 files changed, 440 insertions(+), 141 deletions(-) diff --git a/NEWS.md b/NEWS.md index 879867b6..7572ee94 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,7 +9,9 @@ Red Panda C++ Version 1.5 - change: don't show syntax check messages in the tools output panel (to reduce longtime memory usage) - fix: minor memory leaks when set itemmodels - fix: thread for parsing doesn't correctly released when parsing finished ( so and the parser) - + - enhancement: save project's bookmark in it's own bookmark file + - enhancement: project and non-project files use different bookmark view (auto switch when switch editors) + - enhancement: auto merge when save bookmarks. Red Panda C++ Version 1.4 diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index bea4ccf8..ec15e359 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -1292,6 +1292,7 @@ void Editor::showEvent(QShowEvent */*event*/) reparse(); } + pMainWindow->bookmarkModel()->setIsForProject(inProject()); // if (pSettings->codeCompletion().clearWhenEditorHidden() // && !inProject()) { // reparse(); @@ -1696,7 +1697,7 @@ void Editor::onLinesDeleted(int first, int count) { pMainWindow->caretList().linesDeleted(this,first,count); pMainWindow->debugger()->breakpointModel()->onFileDeleteLines(mFilename,first,count); - pMainWindow->bookmarkModel()->onFileDeleteLines(mFilename,first,count); + pMainWindow->bookmarkModel()->onFileDeleteLines(mFilename,first,count, inProject()); resetBreakpoints(); resetBookmarks(); if (!pSettings->editor().syntaxCheckWhenLineChanged()) { @@ -1708,7 +1709,7 @@ void Editor::onLinesInserted(int first, int count) { pMainWindow->caretList().linesInserted(this,first,count); pMainWindow->debugger()->breakpointModel()->onFileInsertLines(mFilename,first,count); - pMainWindow->bookmarkModel()->onFileInsertLines(mFilename,first,count); + pMainWindow->bookmarkModel()->onFileInsertLines(mFilename,first,count, inProject()); resetBreakpoints(); resetBookmarks(); if (!pSettings->editor().syntaxCheckWhenLineChanged()) { @@ -1747,7 +1748,7 @@ bool Editor::shouldOpenInReadonly() void Editor::resetBookmarks() { - mBookmarkLines=pMainWindow->bookmarkModel()->bookmarksInFile(mFilename); + mBookmarkLines=pMainWindow->bookmarkModel()->bookmarksInFile(mFilename,inProject()); invalidate(); } @@ -4407,17 +4408,15 @@ bool Editor::hasBreakpoint(int line) return mBreakpointLines.contains(line); } -void Editor::addBookmark(int line, const QString& description) +void Editor::addBookmark(int line) { mBookmarkLines.insert(line); - pMainWindow->bookmarkModel()->addBookmark(mFilename,line,description); invalidateGutterLine(line); } void Editor::removeBookmark(int line) { mBookmarkLines.remove(line); - pMainWindow->bookmarkModel()->removeBookmark(mFilename,line); invalidateGutterLine(line); } @@ -4429,7 +4428,6 @@ bool Editor::hasBookmark(int line) void Editor::clearBookmarks() { mBookmarkLines.clear(); - pMainWindow->bookmarkModel()->removeBookmarks(mFilename); invalidateGutter(); } diff --git a/RedPandaIDE/editor.h b/RedPandaIDE/editor.h index e953ac4f..5699750e 100644 --- a/RedPandaIDE/editor.h +++ b/RedPandaIDE/editor.h @@ -187,7 +187,7 @@ public: void toggleBreakpoint(int line); void clearBreakpoints(); bool hasBreakpoint(int line); - void addBookmark(int line,const QString& description); + void addBookmark(int line); void removeBookmark(int line); bool hasBookmark(int line); void clearBookmarks(); @@ -224,6 +224,7 @@ public: QString getWordForCompletionSearch(const QSynedit::BufferCoord& pos,bool permitTilde); QStringList getExpressionAtPosition( const QSynedit::BufferCoord& pos); + void resetBookmarks(); const PCppParser &parser(); @@ -242,7 +243,6 @@ private slots: private: bool isBraceChar(QChar ch); bool shouldOpenInReadonly(); - void resetBookmarks(); QChar getCurrentChar(); bool handleSymbolCompletion(QChar key); bool handleParentheseCompletion(); diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index cde797c8..90ff47a2 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -281,7 +281,7 @@ MainWindow::MainWindow(QWidget *parent) } mBookmarkModel = std::make_shared(); try { - mBookmarkModel->load(includeTrailingPathDelimiter(pSettings->dirs().config()) + mBookmarkModel->loadBookmarks(includeTrailingPathDelimiter(pSettings->dirs().config()) +DEV_BOOKMARK_FILE); } catch (FileError &e) { QMessageBox::warning(nullptr, @@ -407,6 +407,7 @@ MainWindow::MainWindow(QWidget *parent) updateShortcuts(); updateTools(); updateEditorSettings(); + //updateEditorBookmarks(); } MainWindow::~MainWindow() @@ -449,6 +450,14 @@ void MainWindow::updateEditorSettings() mEditorList->applySettings(); } +void MainWindow::updateEditorBookmarks() +{ + for (int i=0;ipageCount();i++) { + Editor * e=(*mEditorList)[i]; + e->resetBookmarks(); + } +} + void MainWindow::updateEditorActions() { Editor* e = mEditorList->getEditor(); @@ -1281,45 +1290,50 @@ void MainWindow::openProject(const QString &filename, bool openFiles) // Only update class browser once mClassBrowserModel.beginUpdate(); - { - auto action = finally([this]{ - mClassBrowserModel.endUpdate(); - }); - mProject = Project::load(filename,mEditorList,&mFileSystemWatcher); - updateProjectView(); - ui->projectView->expand( - mProjectProxyModel->mapFromSource( - mProject->model()->rootIndex())); - pSettings->history().removeProject(filename); + mProject = Project::load(filename,mEditorList,&mFileSystemWatcher); + updateProjectView(); + ui->projectView->expand( + mProjectProxyModel->mapFromSource( + mProject->model()->rootIndex())); + pSettings->history().removeProject(filename); - // // if project manager isn't open then open it - // if not devData.ShowLeftPages then - // actProjectManager.Execute; - //checkForDllProfiling(); +// // if project manager isn't open then open it +// if not devData.ShowLeftPages then +// actProjectManager.Execute; + //checkForDllProfiling(); - //parse the project - // UpdateClassBrowsing; + //parse the project + // UpdateClassBrowsing; - scanActiveProject(true); - if (openFiles) { - PProjectUnit unit = mProject->doAutoOpen(); - setProjectViewCurrentUnit(unit); - } + scanActiveProject(true); - //update editor's inproject flag - foreach (PProjectUnit unit, mProject->unitList()) { - Editor* e = mEditorList->getOpenedEditorByFilename(unit->fileName()); - mProject->associateEditorToUnit(e,unit); - } + mBookmarkModel->setIsForProject(true); + mBookmarkModel->loadProjectBookmarks( + changeFileExt(mProject->filename(), PROJECT_BOOKMARKS_EXT), + mProject->directory()); - Editor * e = mEditorList->getEditor(); - if (e) { - checkSyntaxInBack(e); - } - updateAppTitle(); - updateCompilerSet(); - updateClassBrowserForEditor(e); + if (openFiles) { + PProjectUnit unit = mProject->doAutoOpen(); + setProjectViewCurrentUnit(unit); } + + //update editor's inproject flag + foreach (PProjectUnit unit, mProject->unitList()) { + Editor* e = mEditorList->getOpenedEditorByFilename(unit->fileName()); + mProject->associateEditorToUnit(e,unit); + if (e) + e->resetBookmarks(); + } + + Editor * e = mEditorList->getEditor(); + if (e) { + checkSyntaxInBack(e); + } + updateAppTitle(); + updateCompilerSet(); + updateClassBrowserForEditor(e); + mClassBrowserModel.endUpdate(); + //updateForEncodingInfo(); } @@ -2294,8 +2308,10 @@ void MainWindow::loadLastOpens() focusedEditor = editor; pSettings->history().removeFile(editorFilename); } - if (mProject && mEditorList->pageCount()==0) + if (mProject && mEditorList->pageCount()==0) { mProject->doAutoOpen(); + updateEditorBookmarks(); + } if (count>0) { updateEditorActions(); //updateForEncodingInfo(); @@ -3759,21 +3775,21 @@ void MainWindow::onBookmarkRemove() PBookmark bookmark = mBookmarkModel->bookmark(index.row()); if (bookmark) { Editor * editor = mEditorList->getOpenedEditorByFilename(bookmark->filename); - if (editor) { + if (editor && editor->inProject() == mBookmarkModel->isForProject()) { editor->removeBookmark(bookmark->line); - } else { - mBookmarkModel->removeBookmarkAt(index.row()); } + mBookmarkModel->removeBookmarkAt(index.row()); } } } void MainWindow::onBookmarkRemoveAll() { - mBookmarkModel->clear(); + mBookmarkModel->clear(mBookmarkModel->isForProject()); for (int i=0;ipageCount();i++) { Editor * editor = (*mEditorList)[i]; - editor->clearBookmarks(); + if (editor->inProject() == mBookmarkModel->isForProject()) + editor->clearBookmarks(); } } @@ -4305,33 +4321,31 @@ void MainWindow::closeProject(bool refreshEditor) } else mProject->saveLayout(); // always save layout, but not when SaveAll has been called + mBookmarkModel->saveProjectBookmarks( + changeFileExt(mProject->filename(), PROJECT_BOOKMARKS_EXT), + mProject->directory()); + mClassBrowserModel.beginUpdate(); - { - auto action2 = finally([this]{ - mClassBrowserModel.endUpdate(); - }); - // Remember it - pSettings->history().addToOpenedProjects(mProject->filename()); + // Remember it + pSettings->history().addToOpenedProjects(mProject->filename()); - mEditorList->beginUpdate(); - { - auto action3 = finally([this]{ - mEditorList->endUpdate(); - }); - mProject.reset(); + mEditorList->beginUpdate(); + mProject.reset(); - if (!mQuitting && refreshEditor) { - //reset Class browsing - ui->tabExplorer->setCurrentWidget(ui->tabStructure); - Editor * e = mEditorList->getEditor(); - updateClassBrowserForEditor(e); - } else { - mClassBrowserModel.setParser(nullptr); - mClassBrowserModel.setCurrentFile(""); - } - } + if (!mQuitting && refreshEditor) { + //reset Class browsing + ui->tabExplorer->setCurrentWidget(ui->tabStructure); + Editor * e = mEditorList->getEditor(); + updateClassBrowserForEditor(e); + } else { + mClassBrowserModel.setParser(nullptr); + mClassBrowserModel.setCurrentFile(""); } + mEditorList->endUpdate(); + mClassBrowserModel.endUpdate(); + if (!mQuitting) { + mBookmarkModel->setIsForProject(false); // Clear error browser clearIssues(); updateProjectView(); @@ -4540,7 +4554,7 @@ void MainWindow::closeEvent(QCloseEvent *event) { pSettings->environment().setDefaultOpenFolder(QDir::currentPath()); pSettings->environment().save(); try { - mBookmarkModel->save(includeTrailingPathDelimiter(pSettings->dirs().config()) + mBookmarkModel->saveBookmarks(includeTrailingPathDelimiter(pSettings->dirs().config()) +DEV_BOOKMARK_FILE); } catch (FileError& e) { QMessageBox::warning(nullptr, @@ -4672,8 +4686,8 @@ void MainWindow::on_actionSave_triggered() if (editor != NULL) { try { editor->save(); - if (editor->inProject() && (mProject)) - mProject->saveAll(); +// if (editor->inProject() && (mProject)) +// mProject->saveAll(); } catch(FileError e) { QMessageBox::critical(editor,tr("Error"),e.reason()); } @@ -6942,7 +6956,8 @@ void MainWindow::on_actionAdd_bookmark_triggered() tr("Description:"),QLineEdit::Normal, editor->document()->getString(line-1).trimmed()); desc = desc.trimmed(); - editor->addBookmark(line,desc); + editor->addBookmark(line); + mBookmarkModel->addBookmark(editor->filename(),line,desc,editor->inProject()); } } @@ -6953,6 +6968,7 @@ void MainWindow::on_actionRemove_Bookmark_triggered() int line; if (editor && editor->pointToLine(mEditorContextMenuPos,line)) { editor->removeBookmark(line); + mBookmarkModel->removeBookmark(editor->filename(),line,editor->inProject()); } } diff --git a/RedPandaIDE/mainwindow.h b/RedPandaIDE/mainwindow.h index 273c3d22..500bdc2a 100644 --- a/RedPandaIDE/mainwindow.h +++ b/RedPandaIDE/mainwindow.h @@ -110,6 +110,7 @@ public: void updateForStatusbarModeInfo(bool clear=false); void updateStatusbarMessage(const QString& s); void updateEditorSettings(); + void updateEditorBookmarks(); void updateEditorActions(); void updateProjectActions(); void updateCompileActions(); diff --git a/RedPandaIDE/mainwindow.ui b/RedPandaIDE/mainwindow.ui index 469397b8..3401325d 100644 --- a/RedPandaIDE/mainwindow.ui +++ b/RedPandaIDE/mainwindow.ui @@ -895,7 +895,7 @@ QTabWidget::South - 1 + 5 @@ -1512,6 +1512,9 @@ QAbstractItemView::SelectRows + + true + true diff --git a/RedPandaIDE/systemconsts.h b/RedPandaIDE/systemconsts.h index 1dda7332..5c245717 100644 --- a/RedPandaIDE/systemconsts.h +++ b/RedPandaIDE/systemconsts.h @@ -70,6 +70,7 @@ #endif #define DEV_PROJECT_EXT "dev" +#define PROJECT_BOOKMARKS_EXT "bookmarks" #define RC_EXT "rc" #define RES_EXT "res" #define H_EXT "h" diff --git a/RedPandaIDE/widgets/bookmarkmodel.cpp b/RedPandaIDE/widgets/bookmarkmodel.cpp index dfb48101..5f4fba39 100644 --- a/RedPandaIDE/widgets/bookmarkmodel.cpp +++ b/RedPandaIDE/widgets/bookmarkmodel.cpp @@ -17,6 +17,7 @@ #include "bookmarkmodel.h" #include "../systemconsts.h" +#include #include #include #include @@ -26,15 +27,21 @@ #include #include "../utils.h" -BookmarkModel::BookmarkModel(QObject* parent):QAbstractTableModel(parent) +BookmarkModel::BookmarkModel(QObject* parent):QAbstractTableModel(parent), + mIsForProject(false) { } -QSet BookmarkModel::bookmarksInFile(const QString &filename) +QSet BookmarkModel::bookmarksInFile(const QString &filename, bool forProject) { QSet lines; - foreach (const PBookmark& bookmark, mBookmarks) { + QList bookmarks; + if (forProject) + bookmarks = mProjectBookmarks; + else + bookmarks = mBookmarks; + foreach (const PBookmark& bookmark, bookmarks) { if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0) { lines.insert(bookmark->line); } @@ -42,27 +49,48 @@ QSet BookmarkModel::bookmarksInFile(const QString &filename) return lines; } -void BookmarkModel::addBookmark(const QString &filename, int line, const QString &description) +void BookmarkModel::addBookmark(const QString &filename, int line, const QString &description, bool forProject) { - Q_ASSERT(!isBookmarkExists(filename,line)); + Q_ASSERT(!isBookmarkExists(filename,line,forProject)); PBookmark bookmark = std::make_shared(); bookmark->filename = filename; bookmark->line = line; bookmark->description = description; - beginInsertRows(QModelIndex(),mBookmarks.count(),mBookmarks.count()); - mBookmarks.append(bookmark); - endInsertRows(); + bookmark->timestamp = QDateTime::currentMSecsSinceEpoch(); + if (forProject) { + if (forProject==mIsForProject) + beginInsertRows(QModelIndex(),mProjectBookmarks.count(),mProjectBookmarks.count()); + mProjectBookmarks.append(bookmark); + } else { + if (forProject==mIsForProject) + beginInsertRows(QModelIndex(),mBookmarks.count(),mBookmarks.count()); + mBookmarks.append(bookmark); + } + if (forProject==mIsForProject) + endInsertRows(); +} + +PBookmark BookmarkModel::bookmark(int i, bool forProject) +{ + if (forProject) + return mProjectBookmarks[i]; + else + return mBookmarks[i]; } PBookmark BookmarkModel::bookmark(int i) { - return mBookmarks[i]; + return bookmark(i,isForProject()); } -PBookmark BookmarkModel::bookmark(const QString &filename, int line) +PBookmark BookmarkModel::bookmark(const QString &filename, int line, bool forProject) { - for (int i=0;i bookmarks; + if (forProject) + bookmarks = mProjectBookmarks; + else + bookmarks = mBookmarks; + foreach (PBookmark bookmark, bookmarks) { if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0 && bookmark->line == line) { return bookmark; @@ -71,40 +99,65 @@ PBookmark BookmarkModel::bookmark(const QString &filename, int line) return PBookmark(); } -bool BookmarkModel::removeBookmark(const QString &filename, int line) +PBookmark BookmarkModel::bookmark(const QString &filename, int line) { - for (int i=0;i bookmarks; + if (forProject) + bookmarks = mProjectBookmarks; + else + bookmarks = mBookmarks; + for (int i=0;ifilename.compare(filename, PATH_SENSITIVITY) == 0 && bookmark->line == line) { - removeBookmarkAt(i); + removeBookmarkAt(i, forProject); return true; } } return false; } -void BookmarkModel::removeBookmarks(const QString &filename) +void BookmarkModel::removeBookmarks(const QString &filename, bool forProject) { - for (int i=mBookmarks.count()-1;i>=0;i--) { - PBookmark bookmark = mBookmarks[i]; + QList bookmarks; + if (forProject) + bookmarks = mProjectBookmarks; + else + bookmarks = mBookmarks; + for (int i=bookmarks.count()-1;i>=0;i--) { + PBookmark bookmark = bookmarks[i]; if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0) { - removeBookmarkAt(i); + removeBookmarkAt(i, forProject); } } } -void BookmarkModel::clear() +void BookmarkModel::clear(bool forProject) { - beginResetModel(); - mBookmarks.clear(); - endResetModel(); + if (forProject==mIsForProject) + beginResetModel(); + if (forProject) + mProjectBookmarks.clear(); + else + mBookmarks.clear(); + if (forProject==mIsForProject) + endResetModel(); } -bool BookmarkModel::updateDescription(const QString &filename, int line, const QString &description) +bool BookmarkModel::updateDescription(const QString &filename, int line, const QString &description, bool forProject) { - for (int i=0;i bookmarks; + if (forProject) + bookmarks = mProjectBookmarks; + else + bookmarks = mBookmarks; + for (int i=0;ifilename.compare(filename, PATH_SENSITIVITY) == 0 && bookmark->line == line) { bookmark->description = description; @@ -115,16 +168,90 @@ bool BookmarkModel::updateDescription(const QString &filename, int line, const Q return false; } -void BookmarkModel::save(const QString &filename) +bool BookmarkModel::updateDescription(const QString &filename, int line, const QString &description) { + return updateDescription(filename,line,description,mIsForProject); +} + +void BookmarkModel::saveBookmarks(const QString &filename) +{ + save(filename,QString()); +} + +void BookmarkModel::loadBookmarks(const QString &filename) +{ + if (!mIsForProject) + beginResetModel(); + mBookmarks = load(filename,0,&mLastLoadBookmarksTimestamp); + if (!mIsForProject) + endResetModel(); +} + +void BookmarkModel::save(const QString &filename, const QString& projectFolder) +{ + bool forProject = !projectFolder.isEmpty(); + qint64 t,fileTimestamp; + QList bookmarks; + if (forProject) { + t=mLastLoadProjectBookmarksTimestamp; + foreach (const PBookmark& bookmark, mProjectBookmarks) { + PBookmark newBookmark=std::make_shared(); + newBookmark->description = bookmark->description; + newBookmark->filename = extractRelativePath(projectFolder, bookmark->filename); + newBookmark->line = bookmark->line; + newBookmark->timestamp = bookmark->timestamp; + bookmarks.append(newBookmark); + } + } else { + t=mLastLoadBookmarksTimestamp; + bookmarks = mBookmarks; + } + QList fileBookmarks=load(filename, t,&fileTimestamp); QFile file(filename); - if (file.open(QFile::WriteOnly | QFile::Truncate)) { + int saveOrderCount=0; + if (file.open(QFile::WriteOnly | QFile::Truncate)) { + QHash compareHash; + QList saveBookmarks; + foreach (const PBookmark& bookmark, bookmarks) { + QString key = QString("%1-%2").arg(bookmark->filename).arg(bookmark->line); + bookmark->saveOrder=saveOrderCount++; + compareHash.insert(key,bookmark); + } + foreach (const PBookmark& bookmark, fileBookmarks) { + QString key = QString("%1-%2").arg(bookmark->filename).arg(bookmark->line); + bookmark->saveOrder=saveOrderCount++; + if (!compareHash.contains(key)) + compareHash.insert(key,bookmark); + else { + PBookmark pTemp=compareHash.value(key); + if (pTemp->timestamp<=bookmark->timestamp) + compareHash.insert(key,bookmark); + } + compareHash.insert(key,bookmark); + } + QList saveList; + foreach (const PBookmark& bookmark, compareHash) { + saveList.append(bookmark); + } + std::sort(saveList.begin(),saveList.end(), [](PBookmark b1,PBookmark b2) { + return b1->saveOrder - b2->saveOrder; + }); + + if (forProject) { + mProjectBookmarks=saveList; + mLastLoadProjectBookmarksTimestamp = QDateTime::currentMSecsSinceEpoch(); + } else { + mBookmarks=saveList; + mLastLoadBookmarksTimestamp = QDateTime::currentMSecsSinceEpoch(); + } + QJsonArray array; - foreach (const PBookmark& bookmark, mBookmarks) { + foreach (const PBookmark& bookmark, saveList) { QJsonObject obj; obj["filename"]=bookmark->filename; obj["line"]=bookmark->line; obj["description"]=bookmark->description; + obj["timestamp"]=QString("%1").arg(bookmark->timestamp); array.append(obj); } QJsonDocument doc; @@ -139,12 +266,18 @@ void BookmarkModel::save(const QString &filename) } } -void BookmarkModel::load(const QString& filename) +QList BookmarkModel::load(const QString& filename, qint64 criteriaTimestamp, qint64* pFileTimestamp) { - clear(); + //clear(forProject); + QList bookmarks; + QFileInfo fileInfo(filename); + qint64 timestamp=fileInfo.fileTime(QFile::FileModificationTime).toMSecsSinceEpoch(); + *pFileTimestamp=timestamp; + if (timestamp<=criteriaTimestamp) + return bookmarks; QFile file(filename); if (!file.exists()) - return; + return bookmarks; if (file.open(QFile::ReadOnly)) { QByteArray content = file.readAll(); QJsonParseError error; @@ -156,58 +289,111 @@ void BookmarkModel::load(const QString& filename) .arg(error.errorString())); } QJsonArray array = doc.array(); + qint64 bookmarkTimestamp; + bool ok; for (int i=0;icriteriaTimestamp) { + PBookmark bookmark = std::make_shared(); + bookmark->filename = obj["filename"].toString(); + bookmark->line = obj["line"].toInt(); + bookmark->description = obj["description"].toString(); + bookmark->timestamp=obj["timestamp"].toString().toULongLong(); + bookmarks.append(bookmark); + } } } else { throw FileError(tr("Can't open file '%1' for read.") .arg(filename)); } + return bookmarks; } -void BookmarkModel::onFileDeleteLines(const QString &filename, int startLine, int count) +void BookmarkModel::saveProjectBookmarks(const QString &filename, const QString& projectFolder) { - for (int i = mBookmarks.count()-1;i>=0;i--){ - PBookmark bookmark = mBookmarks[i]; + save(filename,projectFolder); +} + +void BookmarkModel::loadProjectBookmarks(const QString &filename, const QString& projectFolder) +{ + if (mIsForProject) + beginResetModel(); + mProjectBookmarks = load(filename,0,&mLastLoadProjectBookmarksTimestamp); + QDir folder(projectFolder); + foreach (PBookmark bookmark, mProjectBookmarks) { + bookmark->filename=folder.absoluteFilePath(bookmark->filename); + } + if (mIsForProject) + endResetModel(); +} + +void BookmarkModel::onFileDeleteLines(const QString &filename, int startLine, int count, bool forProject) +{ + QList bookmarks; + if (forProject) + bookmarks = mProjectBookmarks; + else + bookmarks = mBookmarks; + for (int i = bookmarks.count()-1;i>=0;i--){ + PBookmark bookmark = bookmarks[i]; if (bookmark->filename == filename && bookmark->line>=startLine) { if (bookmark->line >= startLine+count) { bookmark->line -= count; - emit dataChanged(createIndex(i,0),createIndex(i,2)); + if (forProject == mIsForProject) + emit dataChanged(createIndex(i,0),createIndex(i,2)); } else { - removeBookmarkAt(i); + removeBookmarkAt(i,forProject); } } } } -void BookmarkModel::onFileInsertLines(const QString &filename, int startLine, int count) +void BookmarkModel::onFileInsertLines(const QString &filename, int startLine, int count, bool forProject) { - for (int i = mBookmarks.count()-1;i>=0;i--){ - PBookmark bookmark = mBookmarks[i]; + QList bookmarks; + if (forProject) + bookmarks = mProjectBookmarks; + else + bookmarks = mBookmarks; + for (int i = bookmarks.count()-1;i>=0;i--){ + PBookmark bookmark = bookmarks[i]; if (bookmark->filename == filename && bookmark->line>=startLine) { bookmark->line+=count; - emit dataChanged(createIndex(i,0),createIndex(i,2)); + if (forProject == mIsForProject) + emit dataChanged(createIndex(i,0),createIndex(i,2)); } } } -void BookmarkModel::removeBookmarkAt(int i) +void BookmarkModel::removeBookmarkAt(int i, bool forProject) { - beginRemoveRows(QModelIndex(), i,i); - mBookmarks.removeAt(i); - endRemoveRows(); + if (forProject == mIsForProject) + beginRemoveRows(QModelIndex(), i,i); + if (forProject) + mProjectBookmarks.removeAt(i); + else + mBookmarks.removeAt(i); + if (forProject == mIsForProject) + endRemoveRows(); } -bool BookmarkModel::isBookmarkExists(const QString &filename, int line) +void BookmarkModel::removeBookmarkAt(int i) { - foreach (const PBookmark& bookmark, mBookmarks) { + return removeBookmarkAt(i,isForProject()); +} + +bool BookmarkModel::isBookmarkExists(const QString &filename, int line, bool forProject) +{ + QList bookmarks; + if (forProject) + bookmarks = mProjectBookmarks; + else + bookmarks = mBookmarks; + foreach (const PBookmark& bookmark, bookmarks) { if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0 && bookmark->line == line) { return true; @@ -216,9 +402,77 @@ bool BookmarkModel::isBookmarkExists(const QString &filename, int line) return false; } +bool BookmarkModel::isForProject() const +{ + return mIsForProject; +} + +void BookmarkModel::setIsForProject(bool newIsForProject) +{ + if (newIsForProject!=mIsForProject) { + mIsForProject = newIsForProject; + beginResetModel(); + endResetModel(); + } +} + +void BookmarkModel::sort(int column, Qt::SortOrder order) +{ + switch(column) { + case 0: + if (order == Qt::SortOrder::AscendingOrder) { + auto sorter=[](PBookmark b1,PBookmark b2) { + return QString::compare(b1->description,b2->description); + }; + std::sort(mBookmarks.begin(),mBookmarks.end(),sorter); + std::sort(mProjectBookmarks.begin(),mProjectBookmarks.end(),sorter); + } else { + auto sorter=[](PBookmark b1,PBookmark b2) { + return QString::compare(b2->description,b1->description); + }; + std::sort(mBookmarks.begin(),mBookmarks.end(),sorter); + std::sort(mProjectBookmarks.begin(),mProjectBookmarks.end(),sorter); + } + break; + case 1: + if (order == Qt::SortOrder::AscendingOrder) { + auto sorter=[](PBookmark b1,PBookmark b2) { + return QString::compare(b1->filename,b2->filename); + }; + std::sort(mBookmarks.begin(),mBookmarks.end(),sorter); + std::sort(mProjectBookmarks.begin(),mProjectBookmarks.end(),sorter); + } else { + auto sorter=[](PBookmark b1,PBookmark b2) { + return QString::compare(b2->filename,b1->filename); + }; + std::sort(mBookmarks.begin(),mBookmarks.end(),sorter); + std::sort(mProjectBookmarks.begin(),mProjectBookmarks.end(),sorter); + } + break; + case 2: + if (order == Qt::SortOrder::AscendingOrder) { + auto sorter=[](PBookmark b1,PBookmark b2) { + return b1->line-b2->line; + }; + std::sort(mBookmarks.begin(),mBookmarks.end(),sorter); + std::sort(mProjectBookmarks.begin(),mProjectBookmarks.end(),sorter); + } else { + auto sorter=[](PBookmark b1,PBookmark b2) { + return b2->line-b1->line; + }; + std::sort(mBookmarks.begin(),mBookmarks.end(),sorter); + std::sort(mProjectBookmarks.begin(),mProjectBookmarks.end(),sorter); + } + break; + } +} + int BookmarkModel::rowCount(const QModelIndex &) const { - return mBookmarks.count(); + if (mIsForProject) + return mProjectBookmarks.count(); + else + return mBookmarks.count(); } QVariant BookmarkModel::data(const QModelIndex &index, int role) const @@ -226,7 +480,11 @@ QVariant BookmarkModel::data(const QModelIndex &index, int role) const if (!index.isValid()) return QVariant(); int row = index.row(); - PBookmark bookmark = mBookmarks[row]; + PBookmark bookmark; + if (mIsForProject) + bookmark = mProjectBookmarks[row]; + else + bookmark = mBookmarks[row]; if (role == Qt::DisplayRole) { switch(index.column()) { case 0: diff --git a/RedPandaIDE/widgets/bookmarkmodel.h b/RedPandaIDE/widgets/bookmarkmodel.h index 64418254..e0228c38 100644 --- a/RedPandaIDE/widgets/bookmarkmodel.h +++ b/RedPandaIDE/widgets/bookmarkmodel.h @@ -25,6 +25,8 @@ struct Bookmark { QString filename; int line; QString description; + qint64 timestamp; + int saveOrder; }; using PBookmark=std::shared_ptr; @@ -34,25 +36,37 @@ class BookmarkModel : public QAbstractTableModel Q_OBJECT public: BookmarkModel(QObject* parent=nullptr); - QSet bookmarksInFile(const QString& filename); - void addBookmark(const QString&filename, int line, const QString& description); + QSet bookmarksInFile(const QString& filename, bool forProject); + void addBookmark(const QString&filename, int line, const QString& description, bool forProject); + PBookmark bookmark(int i, bool forProject); PBookmark bookmark(int i); + PBookmark bookmark(const QString&filename, int line, bool forProject); PBookmark bookmark(const QString&filename, int line); - bool removeBookmark(const QString&filename, int line); - void removeBookmarks(const QString& filename); - void clear(); + bool removeBookmark(const QString&filename, int line, bool forProject); + void removeBookmarks(const QString& filename, bool forProject); + void clear(bool forProject); + bool updateDescription(const QString&filename, int line, const QString& description, bool forProject); bool updateDescription(const QString&filename, int line, const QString& description); - void save(const QString& filename); - void load(const QString& filename); + void saveBookmarks(const QString& filename); + void loadBookmarks(const QString& filename); + void saveProjectBookmarks(const QString& filename, const QString& projectFolder); + void loadProjectBookmarks(const QString& filename, const QString& projectFolder); + void removeBookmarkAt(int i, bool forProject); void removeBookmarkAt(int i); public slots: - 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: - bool isBookmarkExists(const QString&filename, int line); + bool isBookmarkExists(const QString&filename, int line, bool forProject); + void save(const QString& filename, const QString& projectFolder); + QList load(const QString& filename, qint64 criteriaTimestamp, qint64* pFileTimestamp); private: QList mBookmarks; + QList mProjectBookmarks; + qint64 mLastLoadBookmarksTimestamp; + qint64 mLastLoadProjectBookmarksTimestamp; + bool mIsForProject; // QAbstractItemModel interface public: @@ -63,6 +77,12 @@ public: // QAbstractItemModel interface public: QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + bool isForProject() const; + void setIsForProject(bool newIsForProject); + + // QAbstractItemModel interface +public: + void sort(int column, Qt::SortOrder order) override; }; using PBookmarkModel = std::shared_ptr;