From b9bb160a6ec421f88793861c62d6db9d6330ab5e Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Date: Tue, 24 Nov 2020 23:41:05 +0500 Subject: [PATCH] Rework tags for performance (#1960) * Optimize tagreload, remove unused method * Use unused count method for counting * Optimize untagged note count * Dont reloadTagTree if the tag panel is not visible --- src/entities/note.cpp | 44 ++++++++++++++---------------- src/entities/note.h | 2 -- src/entities/tag.cpp | 32 +++++++++++++--------- src/entities/tag.h | 11 ++++---- src/mainwindow.cpp | 62 +++++++++++-------------------------------- src/mainwindow.h | 2 -- 6 files changed, 60 insertions(+), 93 deletions(-) diff --git a/src/entities/note.cpp b/src/entities/note.cpp index df616c6eaa..ed144f1cd9 100644 --- a/src/entities/note.cpp +++ b/src/entities/note.cpp @@ -746,27 +746,6 @@ QVector Note::noteIdListFromNoteList(const QVector ¬eList) { return idList; } -/** - * Returns all notes that are not tagged - */ -QVector Note::fetchAllNotTagged(int activeNoteSubFolderId) { - QVector noteList; - if (activeNoteSubFolderId < 0) { - noteList = Note::fetchAll(); - } else { - noteList = Note::fetchAllByNoteSubFolderId(activeNoteSubFolderId); - } - QVector untaggedNoteList; - untaggedNoteList.reserve(noteList.size()); - - QVector::const_iterator i; - for (i = noteList.constBegin(); i != noteList.constEnd(); ++i) { - const int tagCount = Tag::countAllOfNote(*i); - if (tagCount == 0) untaggedNoteList.append(*i); - } - return untaggedNoteList; -} - /** * Returns all notes names that are not tagged */ @@ -777,8 +756,9 @@ QVector Note::fetchAllNotTaggedIds() { QVector::const_iterator it = noteList.constBegin(); for (; it != noteList.constEnd(); ++it) { - const int tagCount = Tag::countAllOfNote(*it); - if (tagCount == 0) untaggedNoteIdList << it->getId(); + if (!Tag::noteHasTags(*it, QString())) { + untaggedNoteIdList << it->getId(); + } } return untaggedNoteIdList; @@ -788,7 +768,23 @@ QVector Note::fetchAllNotTaggedIds() { * Counts all notes that are not tagged */ int Note::countAllNotTagged(int activeNoteSubFolderId) { - return Note::fetchAllNotTagged(activeNoteSubFolderId).count(); + QVector noteList; + QString path; + if (activeNoteSubFolderId < 0) { + noteList = Note::fetchAll(); + } else { + noteList = Note::fetchAllByNoteSubFolderId(activeNoteSubFolderId); + path = NoteSubFolder::fetch(activeNoteSubFolderId).relativePath(); + } + + QVector::const_iterator i; + int count = 0; + for (i = noteList.constBegin(); i != noteList.constEnd(); ++i) { + if (!Tag::noteHasTags(*i, path)) { + count++; + } + } + return count; } QVector Note::search(const QString &text) { diff --git a/src/entities/note.h b/src/entities/note.h index a886843684..beb5031256 100644 --- a/src/entities/note.h +++ b/src/entities/note.h @@ -66,8 +66,6 @@ class Note { static QVector fetchAll(int limit = -1); - static QVector fetchAllNotTagged(int activeNoteSubFolderId); - static QVector fetchAllNotTaggedIds(); static int countAllNotTagged(int activeNoteSubFolderId = -1); diff --git a/src/entities/tag.cpp b/src/entities/tag.cpp index 84ca678fef..37d685b697 100644 --- a/src/entities/tag.cpp +++ b/src/entities/tag.cpp @@ -583,19 +583,20 @@ Tag Tag::fetchOneOfNoteWithColor(const Note ¬e) { } /** - * Count all linked tags of a note + * Checks if a note has tags */ -int Tag::countAllOfNote(const Note ¬e) { +bool Tag::noteHasTags(const Note ¬e, const QString& path) { QSqlDatabase db = DatabaseService::getNoteFolderDatabase(); QSqlQuery query(db); query.prepare( - QStringLiteral("SELECT COUNT(*) AS cnt FROM noteTagLink " - "WHERE note_file_name = :fileName AND " - "note_sub_folder_path = :noteSubFolderPath")); + QStringLiteral("SELECT " + "EXISTS (SELECT tag_id FROM noteTagLink " + "WHERE note_file_name=:fileName AND " + "note_sub_folder_path=:noteSubFolderPath) AS cnt")); query.bindValue(QStringLiteral(":fileName"), note.getName()); query.bindValue(QStringLiteral(":noteSubFolderPath"), - note.getNoteSubFolder().relativePath()); + path.isEmpty() ? note.getNoteSubFolder().relativePath() : path); if (!query.exec()) { qWarning() << __func__ << ": " << query.lastError(); @@ -603,7 +604,7 @@ int Tag::countAllOfNote(const Note ¬e) { int result = query.value(QStringLiteral("cnt")).toInt(); DatabaseService::closeDatabaseConnection(db, query); - return result; + return result == 1; } DatabaseService::closeDatabaseConnection(db, query); @@ -871,11 +872,16 @@ QStringList Tag::fetchAllNames() { * Count the linked note file names for a note sub folder */ int Tag::countLinkedNoteFileNamesForNoteSubFolder( - const NoteSubFolder ¬eSubFolder, const bool recursive) const { + int tagId, const NoteSubFolder ¬eSubFolder, + bool fromAllSubfolders, const bool recursive) { QSqlDatabase db = DatabaseService::getNoteFolderDatabase(); QSqlQuery query(db); - if (recursive) { + if (fromAllSubfolders) { + query.prepare(QStringLiteral( + "SELECT COUNT(note_file_name) AS cnt FROM noteTagLink " + "WHERE tag_id = :id")); + } else if (recursive) { query.prepare(QStringLiteral( "SELECT COUNT(note_file_name) AS cnt FROM noteTagLink " "WHERE tag_id = :id AND " @@ -890,7 +896,7 @@ int Tag::countLinkedNoteFileNamesForNoteSubFolder( query.bindValue(QStringLiteral(":noteSubFolderPath"), noteSubFolder.relativePath() + QLatin1Char('%')); } - query.bindValue(QStringLiteral(":id"), _id); + query.bindValue(QStringLiteral(":id"), tagId); if (!query.exec()) { qWarning() << __func__ << ": " << query.lastError(); @@ -909,8 +915,8 @@ int Tag::countLinkedNoteFileNamesForNoteSubFolder( /** * Count the linked note file names */ -int Tag::countLinkedNoteFileNames(const bool fromAllSubfolders, - const bool recursive) const { +int Tag::countLinkedNoteFileNames(int tagId, bool fromAllSubfolders, + bool recursive) { QSqlDatabase db = DatabaseService::getNoteFolderDatabase(); QSqlQuery query(db); @@ -934,7 +940,7 @@ int Tag::countLinkedNoteFileNames(const bool fromAllSubfolders, query.bindValue(QStringLiteral(":noteSubFolderPath"), NoteSubFolder::activeNoteSubFolder().relativePath()); } - query.bindValue(QStringLiteral(":id"), _id); + query.bindValue(QStringLiteral(":id"), tagId); if (!query.exec()) { qWarning() << __func__ << ": " << query.lastError(); diff --git a/src/entities/tag.h b/src/entities/tag.h index a3edff628c..ffe2ee032f 100644 --- a/src/entities/tag.h +++ b/src/entities/tag.h @@ -75,11 +75,12 @@ class Tag : protected TagHeader { bool isLinkedToNote(const Note ¬e) const; - int countLinkedNoteFileNames(const bool fromAllSubfolder, - const bool recursive) const; + static int countLinkedNoteFileNames(int tagId, bool fromAllSubfolders, + bool recursive); - int countLinkedNoteFileNamesForNoteSubFolder( - const NoteSubFolder ¬eSubFolder, const bool recursive) const; + static int countLinkedNoteFileNamesForNoteSubFolder( + int tagId, const NoteSubFolder ¬eSubFolder, + bool fromAllSubfolders, bool recursive); int getParentId() const; @@ -138,7 +139,7 @@ class Tag : protected TagHeader { static int countAllParentId(const int parentId); - static int countAllOfNote(const Note ¬e); + static bool noteHasTags(const Note ¬e, const QString& path); static void setAsActive(const int tagId); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 4dfb5a24d9..acb4100ed1 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -8011,6 +8011,7 @@ void MainWindow::reloadTagTree() { QIcon::fromTheme(QStringLiteral("edit-copy"), QIcon(QStringLiteral( ":icons/breeze-qownnotes/16x16/edit-copy.svg")))); + // this time, the tags come first buildTagTreeForParentItem(); // and get sorted @@ -8299,7 +8300,7 @@ QTreeWidgetItem *MainWindow::addTagToTagTreeWidget(QTreeWidgetItem *parent, const QString name = tag._name; auto hideCount = QSettings().value("tagsPanelHideNoteCount", false).toBool(); - QVector linkedNoteIds; + int count = 0; if (!hideCount) { const QVector tagIdListToCount = Tag::isTaggingShowNotesRecursively() ? Tag::fetchTagIdsRecursivelyByParentId(tagId) : QVector{tag._id}; @@ -8310,7 +8311,6 @@ QTreeWidgetItem *MainWindow::addTagToTagTreeWidget(QTreeWidgetItem *parent, NoteSubFolder::isNoteSubfoldersPanelShowNotesRecursively(); if (selectedSubFolderItems.count() > 1) { - linkedNoteIds.reserve(tagIdListToCount.size()); for (const int tagIdToCount : tagIdListToCount) { for (QTreeWidgetItem *folderItem : selectedSubFolderItems) { int id = folderItem->data(0, Qt::UserRole).toInt(); @@ -8320,29 +8320,22 @@ QTreeWidgetItem *MainWindow::addTagToTagTreeWidget(QTreeWidgetItem *parent, continue; } - linkedNoteIds << Tag::fetchAllLinkedNoteIdsForFolder( - tagIdToCount, - folder, showNotesFromAllSubFolders, - isShowNotesRecursively); + count = Tag::countLinkedNoteFileNamesForNoteSubFolder( + tagIdToCount, folder, + showNotesFromAllSubFolders, isShowNotesRecursively); } } } else { - linkedNoteIds.reserve(tagIdListToCount.size()); for (const int tagToCount : tagIdListToCount) { - linkedNoteIds << Tag::fetchAllLinkedNoteIds( + count = Tag::countLinkedNoteFileNames( tagToCount, showNotesFromAllSubFolders, isShowNotesRecursively); } } - - // remove duplicate note ids - linkedNoteIds.erase( - std::unique(linkedNoteIds.begin(), linkedNoteIds.end()), - linkedNoteIds.end()); } - const int linkCount = linkedNoteIds.count(); + const int linkCount = count; const QString toolTip = tr("show all notes tagged with '%1' (%2)") .arg(name, QString::number(linkCount)); auto *item = new QTreeWidgetItem(); @@ -9796,33 +9789,6 @@ void MainWindow::copySelectedNotesToNoteSubFolder( } } -/** - * Returns true if one of the selected notes has a linked tag - * - * @return - */ -bool MainWindow::selectedNotesHaveTags() { - const auto items = ui->noteTreeWidget->selectedItems(); - for (QTreeWidgetItem *item : items) { - if (item->data(0, Qt::UserRole + 1) != NoteType) { - continue; - } - - const int noteId = item->data(0, Qt::UserRole).toInt(); - const Note note = Note::fetch(noteId); - - if (!note.isFetched()) { - continue; - } - - if (Tag::countAllOfNote(note) > 0) { - return true; - } - } - - return false; -} - /** * Opens the widget to replace text in the current note */ @@ -10718,21 +10684,23 @@ void MainWindow::on_noteSubFolderTreeWidget_currentItemChanged( filterNotes(); } - reloadTagTree(); + if (isTagsEnabled()) { + reloadTagTree(); + } } void MainWindow::on_noteSubFolderTreeWidget_itemSelectionChanged() { const auto items = ui->noteSubFolderTreeWidget->selectedItems(); // if no items selected or only one selected if (ui->noteSubFolderTreeWidget->selectedItems().count() <= 1) { - if (items.count() == 1) { - // on_noteSubFolderTreeWidget_currentItemChanged(items.first(), - // Q_NULLPTR); - } return; } + filterNotes(); - reloadTagTree(); + + if (isTagsEnabled()) { + reloadTagTree(); + } } void MainWindow::clearTagFilteringColumn() { diff --git a/src/mainwindow.h b/src/mainwindow.h index e381ec68fd..320f4d350b 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -954,8 +954,6 @@ class MainWindow : public QMainWindow { void createNewNote(QString noteName = QString(), bool withNameAppend = true); - bool selectedNotesHaveTags(); - void initTagButtonScrollArea(); static QIcon getSystemTrayIcon();