- 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.
This commit is contained in:
Roy Qu 2022-10-11 21:51:33 +08:00
parent f67628863f
commit 975d90c8f1
9 changed files with 440 additions and 141 deletions

View File

@ -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) - 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: minor memory leaks when set itemmodels
- fix: thread for parsing doesn't correctly released when parsing finished ( so and the parser) - 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 Red Panda C++ Version 1.4

View File

@ -1292,6 +1292,7 @@ void Editor::showEvent(QShowEvent */*event*/)
reparse(); reparse();
} }
pMainWindow->bookmarkModel()->setIsForProject(inProject());
// if (pSettings->codeCompletion().clearWhenEditorHidden() // if (pSettings->codeCompletion().clearWhenEditorHidden()
// && !inProject()) { // && !inProject()) {
// reparse(); // reparse();
@ -1696,7 +1697,7 @@ void Editor::onLinesDeleted(int first, int count)
{ {
pMainWindow->caretList().linesDeleted(this,first,count); pMainWindow->caretList().linesDeleted(this,first,count);
pMainWindow->debugger()->breakpointModel()->onFileDeleteLines(mFilename,first,count); pMainWindow->debugger()->breakpointModel()->onFileDeleteLines(mFilename,first,count);
pMainWindow->bookmarkModel()->onFileDeleteLines(mFilename,first,count); pMainWindow->bookmarkModel()->onFileDeleteLines(mFilename,first,count, inProject());
resetBreakpoints(); resetBreakpoints();
resetBookmarks(); resetBookmarks();
if (!pSettings->editor().syntaxCheckWhenLineChanged()) { if (!pSettings->editor().syntaxCheckWhenLineChanged()) {
@ -1708,7 +1709,7 @@ void Editor::onLinesInserted(int first, int count)
{ {
pMainWindow->caretList().linesInserted(this,first,count); pMainWindow->caretList().linesInserted(this,first,count);
pMainWindow->debugger()->breakpointModel()->onFileInsertLines(mFilename,first,count); pMainWindow->debugger()->breakpointModel()->onFileInsertLines(mFilename,first,count);
pMainWindow->bookmarkModel()->onFileInsertLines(mFilename,first,count); pMainWindow->bookmarkModel()->onFileInsertLines(mFilename,first,count, inProject());
resetBreakpoints(); resetBreakpoints();
resetBookmarks(); resetBookmarks();
if (!pSettings->editor().syntaxCheckWhenLineChanged()) { if (!pSettings->editor().syntaxCheckWhenLineChanged()) {
@ -1747,7 +1748,7 @@ bool Editor::shouldOpenInReadonly()
void Editor::resetBookmarks() void Editor::resetBookmarks()
{ {
mBookmarkLines=pMainWindow->bookmarkModel()->bookmarksInFile(mFilename); mBookmarkLines=pMainWindow->bookmarkModel()->bookmarksInFile(mFilename,inProject());
invalidate(); invalidate();
} }
@ -4407,17 +4408,15 @@ bool Editor::hasBreakpoint(int line)
return mBreakpointLines.contains(line); return mBreakpointLines.contains(line);
} }
void Editor::addBookmark(int line, const QString& description) void Editor::addBookmark(int line)
{ {
mBookmarkLines.insert(line); mBookmarkLines.insert(line);
pMainWindow->bookmarkModel()->addBookmark(mFilename,line,description);
invalidateGutterLine(line); invalidateGutterLine(line);
} }
void Editor::removeBookmark(int line) void Editor::removeBookmark(int line)
{ {
mBookmarkLines.remove(line); mBookmarkLines.remove(line);
pMainWindow->bookmarkModel()->removeBookmark(mFilename,line);
invalidateGutterLine(line); invalidateGutterLine(line);
} }
@ -4429,7 +4428,6 @@ bool Editor::hasBookmark(int line)
void Editor::clearBookmarks() void Editor::clearBookmarks()
{ {
mBookmarkLines.clear(); mBookmarkLines.clear();
pMainWindow->bookmarkModel()->removeBookmarks(mFilename);
invalidateGutter(); invalidateGutter();
} }

View File

@ -187,7 +187,7 @@ public:
void toggleBreakpoint(int line); void toggleBreakpoint(int line);
void clearBreakpoints(); void clearBreakpoints();
bool hasBreakpoint(int line); bool hasBreakpoint(int line);
void addBookmark(int line,const QString& description); void addBookmark(int line);
void removeBookmark(int line); void removeBookmark(int line);
bool hasBookmark(int line); bool hasBookmark(int line);
void clearBookmarks(); void clearBookmarks();
@ -224,6 +224,7 @@ public:
QString getWordForCompletionSearch(const QSynedit::BufferCoord& pos,bool permitTilde); QString getWordForCompletionSearch(const QSynedit::BufferCoord& pos,bool permitTilde);
QStringList getExpressionAtPosition( QStringList getExpressionAtPosition(
const QSynedit::BufferCoord& pos); const QSynedit::BufferCoord& pos);
void resetBookmarks();
const PCppParser &parser(); const PCppParser &parser();
@ -242,7 +243,6 @@ private slots:
private: private:
bool isBraceChar(QChar ch); bool isBraceChar(QChar ch);
bool shouldOpenInReadonly(); bool shouldOpenInReadonly();
void resetBookmarks();
QChar getCurrentChar(); QChar getCurrentChar();
bool handleSymbolCompletion(QChar key); bool handleSymbolCompletion(QChar key);
bool handleParentheseCompletion(); bool handleParentheseCompletion();

View File

@ -281,7 +281,7 @@ MainWindow::MainWindow(QWidget *parent)
} }
mBookmarkModel = std::make_shared<BookmarkModel>(); mBookmarkModel = std::make_shared<BookmarkModel>();
try { try {
mBookmarkModel->load(includeTrailingPathDelimiter(pSettings->dirs().config()) mBookmarkModel->loadBookmarks(includeTrailingPathDelimiter(pSettings->dirs().config())
+DEV_BOOKMARK_FILE); +DEV_BOOKMARK_FILE);
} catch (FileError &e) { } catch (FileError &e) {
QMessageBox::warning(nullptr, QMessageBox::warning(nullptr,
@ -407,6 +407,7 @@ MainWindow::MainWindow(QWidget *parent)
updateShortcuts(); updateShortcuts();
updateTools(); updateTools();
updateEditorSettings(); updateEditorSettings();
//updateEditorBookmarks();
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
@ -449,6 +450,14 @@ void MainWindow::updateEditorSettings()
mEditorList->applySettings(); mEditorList->applySettings();
} }
void MainWindow::updateEditorBookmarks()
{
for (int i=0;i<mEditorList->pageCount();i++) {
Editor * e=(*mEditorList)[i];
e->resetBookmarks();
}
}
void MainWindow::updateEditorActions() void MainWindow::updateEditorActions()
{ {
Editor* e = mEditorList->getEditor(); Editor* e = mEditorList->getEditor();
@ -1281,45 +1290,50 @@ void MainWindow::openProject(const QString &filename, bool openFiles)
// Only update class browser once // Only update class browser once
mClassBrowserModel.beginUpdate(); mClassBrowserModel.beginUpdate();
{ mProject = Project::load(filename,mEditorList,&mFileSystemWatcher);
auto action = finally([this]{ updateProjectView();
mClassBrowserModel.endUpdate(); ui->projectView->expand(
}); mProjectProxyModel->mapFromSource(
mProject = Project::load(filename,mEditorList,&mFileSystemWatcher); mProject->model()->rootIndex()));
updateProjectView(); pSettings->history().removeProject(filename);
ui->projectView->expand(
mProjectProxyModel->mapFromSource(
mProject->model()->rootIndex()));
pSettings->history().removeProject(filename);
// // if project manager isn't open then open it // // if project manager isn't open then open it
// if not devData.ShowLeftPages then // if not devData.ShowLeftPages then
// actProjectManager.Execute; // actProjectManager.Execute;
//checkForDllProfiling(); //checkForDllProfiling();
//parse the project //parse the project
// UpdateClassBrowsing; // UpdateClassBrowsing;
scanActiveProject(true); scanActiveProject(true);
if (openFiles) {
PProjectUnit unit = mProject->doAutoOpen();
setProjectViewCurrentUnit(unit);
}
//update editor's inproject flag mBookmarkModel->setIsForProject(true);
foreach (PProjectUnit unit, mProject->unitList()) { mBookmarkModel->loadProjectBookmarks(
Editor* e = mEditorList->getOpenedEditorByFilename(unit->fileName()); changeFileExt(mProject->filename(), PROJECT_BOOKMARKS_EXT),
mProject->associateEditorToUnit(e,unit); mProject->directory());
}
Editor * e = mEditorList->getEditor(); if (openFiles) {
if (e) { PProjectUnit unit = mProject->doAutoOpen();
checkSyntaxInBack(e); setProjectViewCurrentUnit(unit);
}
updateAppTitle();
updateCompilerSet();
updateClassBrowserForEditor(e);
} }
//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(); //updateForEncodingInfo();
} }
@ -2294,8 +2308,10 @@ void MainWindow::loadLastOpens()
focusedEditor = editor; focusedEditor = editor;
pSettings->history().removeFile(editorFilename); pSettings->history().removeFile(editorFilename);
} }
if (mProject && mEditorList->pageCount()==0) if (mProject && mEditorList->pageCount()==0) {
mProject->doAutoOpen(); mProject->doAutoOpen();
updateEditorBookmarks();
}
if (count>0) { if (count>0) {
updateEditorActions(); updateEditorActions();
//updateForEncodingInfo(); //updateForEncodingInfo();
@ -3759,21 +3775,21 @@ void MainWindow::onBookmarkRemove()
PBookmark bookmark = mBookmarkModel->bookmark(index.row()); PBookmark bookmark = mBookmarkModel->bookmark(index.row());
if (bookmark) { if (bookmark) {
Editor * editor = mEditorList->getOpenedEditorByFilename(bookmark->filename); Editor * editor = mEditorList->getOpenedEditorByFilename(bookmark->filename);
if (editor) { if (editor && editor->inProject() == mBookmarkModel->isForProject()) {
editor->removeBookmark(bookmark->line); editor->removeBookmark(bookmark->line);
} else {
mBookmarkModel->removeBookmarkAt(index.row());
} }
mBookmarkModel->removeBookmarkAt(index.row());
} }
} }
} }
void MainWindow::onBookmarkRemoveAll() void MainWindow::onBookmarkRemoveAll()
{ {
mBookmarkModel->clear(); mBookmarkModel->clear(mBookmarkModel->isForProject());
for (int i=0;i<mEditorList->pageCount();i++) { for (int i=0;i<mEditorList->pageCount();i++) {
Editor * editor = (*mEditorList)[i]; Editor * editor = (*mEditorList)[i];
editor->clearBookmarks(); if (editor->inProject() == mBookmarkModel->isForProject())
editor->clearBookmarks();
} }
} }
@ -4305,33 +4321,31 @@ void MainWindow::closeProject(bool refreshEditor)
} else } else
mProject->saveLayout(); // always save layout, but not when SaveAll has been called mProject->saveLayout(); // always save layout, but not when SaveAll has been called
mBookmarkModel->saveProjectBookmarks(
changeFileExt(mProject->filename(), PROJECT_BOOKMARKS_EXT),
mProject->directory());
mClassBrowserModel.beginUpdate(); mClassBrowserModel.beginUpdate();
{ // Remember it
auto action2 = finally([this]{ pSettings->history().addToOpenedProjects(mProject->filename());
mClassBrowserModel.endUpdate();
});
// Remember it
pSettings->history().addToOpenedProjects(mProject->filename());
mEditorList->beginUpdate(); mEditorList->beginUpdate();
{ mProject.reset();
auto action3 = finally([this]{
mEditorList->endUpdate();
});
mProject.reset();
if (!mQuitting && refreshEditor) { if (!mQuitting && refreshEditor) {
//reset Class browsing //reset Class browsing
ui->tabExplorer->setCurrentWidget(ui->tabStructure); ui->tabExplorer->setCurrentWidget(ui->tabStructure);
Editor * e = mEditorList->getEditor(); Editor * e = mEditorList->getEditor();
updateClassBrowserForEditor(e); updateClassBrowserForEditor(e);
} else { } else {
mClassBrowserModel.setParser(nullptr); mClassBrowserModel.setParser(nullptr);
mClassBrowserModel.setCurrentFile(""); mClassBrowserModel.setCurrentFile("");
}
}
} }
mEditorList->endUpdate();
mClassBrowserModel.endUpdate();
if (!mQuitting) { if (!mQuitting) {
mBookmarkModel->setIsForProject(false);
// Clear error browser // Clear error browser
clearIssues(); clearIssues();
updateProjectView(); updateProjectView();
@ -4540,7 +4554,7 @@ void MainWindow::closeEvent(QCloseEvent *event) {
pSettings->environment().setDefaultOpenFolder(QDir::currentPath()); pSettings->environment().setDefaultOpenFolder(QDir::currentPath());
pSettings->environment().save(); pSettings->environment().save();
try { try {
mBookmarkModel->save(includeTrailingPathDelimiter(pSettings->dirs().config()) mBookmarkModel->saveBookmarks(includeTrailingPathDelimiter(pSettings->dirs().config())
+DEV_BOOKMARK_FILE); +DEV_BOOKMARK_FILE);
} catch (FileError& e) { } catch (FileError& e) {
QMessageBox::warning(nullptr, QMessageBox::warning(nullptr,
@ -4672,8 +4686,8 @@ void MainWindow::on_actionSave_triggered()
if (editor != NULL) { if (editor != NULL) {
try { try {
editor->save(); editor->save();
if (editor->inProject() && (mProject)) // if (editor->inProject() && (mProject))
mProject->saveAll(); // mProject->saveAll();
} catch(FileError e) { } catch(FileError e) {
QMessageBox::critical(editor,tr("Error"),e.reason()); QMessageBox::critical(editor,tr("Error"),e.reason());
} }
@ -6942,7 +6956,8 @@ void MainWindow::on_actionAdd_bookmark_triggered()
tr("Description:"),QLineEdit::Normal, tr("Description:"),QLineEdit::Normal,
editor->document()->getString(line-1).trimmed()); editor->document()->getString(line-1).trimmed());
desc = desc.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; int line;
if (editor && editor->pointToLine(mEditorContextMenuPos,line)) { if (editor && editor->pointToLine(mEditorContextMenuPos,line)) {
editor->removeBookmark(line); editor->removeBookmark(line);
mBookmarkModel->removeBookmark(editor->filename(),line,editor->inProject());
} }
} }

View File

@ -110,6 +110,7 @@ public:
void updateForStatusbarModeInfo(bool clear=false); void updateForStatusbarModeInfo(bool clear=false);
void updateStatusbarMessage(const QString& s); void updateStatusbarMessage(const QString& s);
void updateEditorSettings(); void updateEditorSettings();
void updateEditorBookmarks();
void updateEditorActions(); void updateEditorActions();
void updateProjectActions(); void updateProjectActions();
void updateCompileActions(); void updateCompileActions();

View File

@ -895,7 +895,7 @@
<enum>QTabWidget::South</enum> <enum>QTabWidget::South</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>1</number> <number>5</number>
</property> </property>
<property name="iconSize"> <property name="iconSize">
<size> <size>
@ -1512,6 +1512,9 @@
<property name="selectionBehavior"> <property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum> <enum>QAbstractItemView::SelectRows</enum>
</property> </property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderStretchLastSection"> <attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool> <bool>true</bool>
</attribute> </attribute>

View File

@ -70,6 +70,7 @@
#endif #endif
#define DEV_PROJECT_EXT "dev" #define DEV_PROJECT_EXT "dev"
#define PROJECT_BOOKMARKS_EXT "bookmarks"
#define RC_EXT "rc" #define RC_EXT "rc"
#define RES_EXT "res" #define RES_EXT "res"
#define H_EXT "h" #define H_EXT "h"

View File

@ -17,6 +17,7 @@
#include "bookmarkmodel.h" #include "bookmarkmodel.h"
#include "../systemconsts.h" #include "../systemconsts.h"
#include <QDir>
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QJsonArray> #include <QJsonArray>
@ -26,15 +27,21 @@
#include <QSet> #include <QSet>
#include "../utils.h" #include "../utils.h"
BookmarkModel::BookmarkModel(QObject* parent):QAbstractTableModel(parent) BookmarkModel::BookmarkModel(QObject* parent):QAbstractTableModel(parent),
mIsForProject(false)
{ {
} }
QSet<int> BookmarkModel::bookmarksInFile(const QString &filename) QSet<int> BookmarkModel::bookmarksInFile(const QString &filename, bool forProject)
{ {
QSet<int> lines; QSet<int> lines;
foreach (const PBookmark& bookmark, mBookmarks) { QList<PBookmark> bookmarks;
if (forProject)
bookmarks = mProjectBookmarks;
else
bookmarks = mBookmarks;
foreach (const PBookmark& bookmark, bookmarks) {
if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0) { if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0) {
lines.insert(bookmark->line); lines.insert(bookmark->line);
} }
@ -42,27 +49,48 @@ QSet<int> BookmarkModel::bookmarksInFile(const QString &filename)
return lines; 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>(); PBookmark bookmark = std::make_shared<Bookmark>();
bookmark->filename = filename; bookmark->filename = filename;
bookmark->line = line; bookmark->line = line;
bookmark->description = description; bookmark->description = description;
beginInsertRows(QModelIndex(),mBookmarks.count(),mBookmarks.count()); bookmark->timestamp = QDateTime::currentMSecsSinceEpoch();
mBookmarks.append(bookmark); if (forProject) {
endInsertRows(); 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) 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<mBookmarks.count();i++) { QList<PBookmark> bookmarks;
PBookmark bookmark = mBookmarks[i]; if (forProject)
bookmarks = mProjectBookmarks;
else
bookmarks = mBookmarks;
foreach (PBookmark bookmark, bookmarks) {
if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0 if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0
&& bookmark->line == line) { && bookmark->line == line) {
return bookmark; return bookmark;
@ -71,40 +99,65 @@ PBookmark BookmarkModel::bookmark(const QString &filename, int line)
return PBookmark(); return PBookmark();
} }
bool BookmarkModel::removeBookmark(const QString &filename, int line) PBookmark BookmarkModel::bookmark(const QString &filename, int line)
{ {
for (int i=0;i<mBookmarks.count();i++) { return bookmark(filename,line,isForProject());
PBookmark bookmark = mBookmarks[i]; }
bool BookmarkModel::removeBookmark(const QString &filename, int line, bool forProject)
{
QList<PBookmark> bookmarks;
if (forProject)
bookmarks = mProjectBookmarks;
else
bookmarks = mBookmarks;
for (int i=0;i<bookmarks.count();i++) {
PBookmark bookmark = bookmarks[i];
if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0 if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0
&& bookmark->line == line) { && bookmark->line == line) {
removeBookmarkAt(i); removeBookmarkAt(i, forProject);
return true; return true;
} }
} }
return false; 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--) { QList<PBookmark> bookmarks;
PBookmark bookmark = mBookmarks[i]; 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) { if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0) {
removeBookmarkAt(i); removeBookmarkAt(i, forProject);
} }
} }
} }
void BookmarkModel::clear() void BookmarkModel::clear(bool forProject)
{ {
beginResetModel(); if (forProject==mIsForProject)
mBookmarks.clear(); beginResetModel();
endResetModel(); 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<mBookmarks.count();i++) { QList<PBookmark> bookmarks;
PBookmark bookmark = mBookmarks[i]; if (forProject)
bookmarks = mProjectBookmarks;
else
bookmarks = mBookmarks;
for (int i=0;i<bookmarks.count();i++) {
PBookmark bookmark = bookmarks[i];
if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0 if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0
&& bookmark->line == line) { && bookmark->line == line) {
bookmark->description = description; bookmark->description = description;
@ -115,16 +168,90 @@ bool BookmarkModel::updateDescription(const QString &filename, int line, const Q
return false; 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<PBookmark> bookmarks;
if (forProject) {
t=mLastLoadProjectBookmarksTimestamp;
foreach (const PBookmark& bookmark, mProjectBookmarks) {
PBookmark newBookmark=std::make_shared<Bookmark>();
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<PBookmark> fileBookmarks=load(filename, t,&fileTimestamp);
QFile file(filename); QFile file(filename);
int saveOrderCount=0;
if (file.open(QFile::WriteOnly | QFile::Truncate)) { if (file.open(QFile::WriteOnly | QFile::Truncate)) {
QHash<QString,PBookmark> compareHash;
QList<PBookmark> 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<PBookmark> 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; QJsonArray array;
foreach (const PBookmark& bookmark, mBookmarks) { foreach (const PBookmark& bookmark, saveList) {
QJsonObject obj; QJsonObject obj;
obj["filename"]=bookmark->filename; obj["filename"]=bookmark->filename;
obj["line"]=bookmark->line; obj["line"]=bookmark->line;
obj["description"]=bookmark->description; obj["description"]=bookmark->description;
obj["timestamp"]=QString("%1").arg(bookmark->timestamp);
array.append(obj); array.append(obj);
} }
QJsonDocument doc; QJsonDocument doc;
@ -139,12 +266,18 @@ void BookmarkModel::save(const QString &filename)
} }
} }
void BookmarkModel::load(const QString& filename) QList<PBookmark> BookmarkModel::load(const QString& filename, qint64 criteriaTimestamp, qint64* pFileTimestamp)
{ {
clear(); //clear(forProject);
QList<PBookmark> bookmarks;
QFileInfo fileInfo(filename);
qint64 timestamp=fileInfo.fileTime(QFile::FileModificationTime).toMSecsSinceEpoch();
*pFileTimestamp=timestamp;
if (timestamp<=criteriaTimestamp)
return bookmarks;
QFile file(filename); QFile file(filename);
if (!file.exists()) if (!file.exists())
return; return bookmarks;
if (file.open(QFile::ReadOnly)) { if (file.open(QFile::ReadOnly)) {
QByteArray content = file.readAll(); QByteArray content = file.readAll();
QJsonParseError error; QJsonParseError error;
@ -156,58 +289,111 @@ void BookmarkModel::load(const QString& filename)
.arg(error.errorString())); .arg(error.errorString()));
} }
QJsonArray array = doc.array(); QJsonArray array = doc.array();
qint64 bookmarkTimestamp;
bool ok;
for (int i=0;i<array.count();i++) { for (int i=0;i<array.count();i++) {
QJsonValue value = array[i]; QJsonValue value = array[i];
QJsonObject obj=value.toObject(); QJsonObject obj=value.toObject();
addBookmark( QFileInfo(obj["filename"].toString()).absoluteFilePath(), bookmarkTimestamp = obj["timestamp"].toString().toULongLong(&ok);
obj["line"].toInt(), if (ok && bookmarkTimestamp>criteriaTimestamp) {
obj["description"].toString()); PBookmark bookmark = std::make_shared<Bookmark>();
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 { } else {
throw FileError(tr("Can't open file '%1' for read.") throw FileError(tr("Can't open file '%1' for read.")
.arg(filename)); .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--){ save(filename,projectFolder);
PBookmark bookmark = mBookmarks[i]; }
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<PBookmark> 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 if (bookmark->filename == filename
&& bookmark->line>=startLine) { && bookmark->line>=startLine) {
if (bookmark->line >= startLine+count) { if (bookmark->line >= startLine+count) {
bookmark->line -= count; bookmark->line -= count;
emit dataChanged(createIndex(i,0),createIndex(i,2)); if (forProject == mIsForProject)
emit dataChanged(createIndex(i,0),createIndex(i,2));
} else { } 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--){ QList<PBookmark> bookmarks;
PBookmark bookmark = mBookmarks[i]; if (forProject)
bookmarks = mProjectBookmarks;
else
bookmarks = mBookmarks;
for (int i = bookmarks.count()-1;i>=0;i--){
PBookmark bookmark = bookmarks[i];
if (bookmark->filename == filename if (bookmark->filename == filename
&& bookmark->line>=startLine) { && bookmark->line>=startLine) {
bookmark->line+=count; 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); if (forProject == mIsForProject)
mBookmarks.removeAt(i); beginRemoveRows(QModelIndex(), i,i);
endRemoveRows(); 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<PBookmark> bookmarks;
if (forProject)
bookmarks = mProjectBookmarks;
else
bookmarks = mBookmarks;
foreach (const PBookmark& bookmark, bookmarks) {
if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0 if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0
&& bookmark->line == line) { && bookmark->line == line) {
return true; return true;
@ -216,9 +402,77 @@ bool BookmarkModel::isBookmarkExists(const QString &filename, int line)
return false; 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 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 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()) if (!index.isValid())
return QVariant(); return QVariant();
int row = index.row(); int row = index.row();
PBookmark bookmark = mBookmarks[row]; PBookmark bookmark;
if (mIsForProject)
bookmark = mProjectBookmarks[row];
else
bookmark = mBookmarks[row];
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
switch(index.column()) { switch(index.column()) {
case 0: case 0:

View File

@ -25,6 +25,8 @@ struct Bookmark {
QString filename; QString filename;
int line; int line;
QString description; QString description;
qint64 timestamp;
int saveOrder;
}; };
using PBookmark=std::shared_ptr<Bookmark>; using PBookmark=std::shared_ptr<Bookmark>;
@ -34,25 +36,37 @@ class BookmarkModel : public QAbstractTableModel
Q_OBJECT Q_OBJECT
public: public:
BookmarkModel(QObject* parent=nullptr); BookmarkModel(QObject* parent=nullptr);
QSet<int> bookmarksInFile(const QString& filename); QSet<int> bookmarksInFile(const QString& filename, bool forProject);
void addBookmark(const QString&filename, int line, const QString& description); void addBookmark(const QString&filename, int line, const QString& description, bool forProject);
PBookmark bookmark(int i, bool forProject);
PBookmark bookmark(int i); PBookmark bookmark(int i);
PBookmark bookmark(const QString&filename, int line, bool forProject);
PBookmark bookmark(const QString&filename, int line); PBookmark bookmark(const QString&filename, int line);
bool removeBookmark(const QString&filename, int line); bool removeBookmark(const QString&filename, int line, bool forProject);
void removeBookmarks(const QString& filename); void removeBookmarks(const QString& filename, bool forProject);
void clear(); 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); bool updateDescription(const QString&filename, int line, const QString& description);
void save(const QString& filename); void saveBookmarks(const QString& filename);
void load(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); void removeBookmarkAt(int i);
public slots: public slots:
void onFileDeleteLines(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); void onFileInsertLines(const QString& filename, int startLine, int count, bool forProject);
private: 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<PBookmark> load(const QString& filename, qint64 criteriaTimestamp, qint64* pFileTimestamp);
private: private:
QList<PBookmark> mBookmarks; QList<PBookmark> mBookmarks;
QList<PBookmark> mProjectBookmarks;
qint64 mLastLoadBookmarksTimestamp;
qint64 mLastLoadProjectBookmarksTimestamp;
bool mIsForProject;
// QAbstractItemModel interface // QAbstractItemModel interface
public: public:
@ -63,6 +77,12 @@ public:
// QAbstractItemModel interface // QAbstractItemModel interface
public: public:
QVariant headerData(int section, Qt::Orientation orientation, int role) const override; 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<BookmarkModel>; using PBookmarkModel = std::shared_ptr<BookmarkModel>;