Line data Source code
1 : #include "UpdateOrdinalsOperation.h"
2 : #include "../models/FeedItem.h"
3 : #include "../models/FolderFeedItem.h"
4 : #include "../models/ListModel.h"
5 : #include "../utilities/UnreadCountReader.h"
6 :
7 : #include <QList>
8 : #include <QSet>
9 : #include <QDebug>
10 :
11 12 : UpdateOrdinalsOperation::UpdateOrdinalsOperation(OperationManager *parent, ListModel *feedList) :
12 : DBOperation(parent),
13 12 : feedList(feedList)
14 : {
15 12 : }
16 :
17 12 : void UpdateOrdinalsOperation::execute()
18 : {
19 12 : QSet<qint64> folderIDs;
20 12 : QList<FeedItem*> removedFromFolder;
21 12 : db().transaction();
22 :
23 : // Update ordinals and gather folder IDs.
24 36 : for (int i = 0; i < feedList->count(); i++) {
25 24 : FeedItem* feedItem = qobject_cast<FeedItem*>(feedList->row(i));
26 24 : if (feedItem->isSpecialFeed()) {
27 1 : continue;
28 : }
29 :
30 : // Track folder IDs for later cleanup.
31 23 : FolderFeedItem* folder = qobject_cast<FolderFeedItem*>(feedItem);
32 23 : if (folder) {
33 8 : folderIDs.insert(folder->getDbID());
34 : }
35 :
36 23 : QSqlQuery update(db());
37 23 : update.prepare("UPDATE FeedItemTable SET ordinal = :ordinal WHERE id = :feed_id");
38 23 : update.bindValue(":ordinal", i);
39 23 : update.bindValue(":feed_id", feedItem->getDbID());
40 :
41 23 : if (!update.exec()) {
42 0 : reportSQLError(update, "Unable to update ordinal for feed id " + QString::number(feedItem->getDbID()));
43 0 : db().rollback();
44 0 : return;
45 : }
46 23 : }
47 :
48 : // Update parent folder associations.
49 36 : for (int i = 0; i < feedList->count(); i++) {
50 24 : FeedItem* feedItem = qobject_cast<FeedItem*>(feedList->row(i));
51 24 : if (feedItem->isSpecialFeed()) {
52 1 : continue;
53 : }
54 :
55 23 : if (!folderIDs.contains(feedItem->getParentFolderID())) {
56 : // Feed's parent folder no longer exists; track for model update later.
57 18 : removedFromFolder << feedItem;
58 : }
59 :
60 23 : QSqlQuery update(db());
61 23 : update.prepare("UPDATE FeedItemTable SET parent_folder = :parent_folder WHERE id = :feed_id");
62 23 : update.bindValue(":parent_folder", feedItem->getParentFolderID());
63 23 : update.bindValue(":feed_id", feedItem->getDbID());
64 :
65 23 : if (!update.exec()) {
66 0 : reportSQLError(update, "Unable to update parent for feed id " + QString::number(feedItem->getDbID()));
67 0 : db().rollback();
68 0 : return;
69 : }
70 23 : }
71 :
72 : // Check for empty folders and remove them from model, DB, and/or both.
73 12 : QSet<qint64> foldersWithChildren;
74 36 : for (int i = 0; i < feedList->count(); i++) {
75 24 : FeedItem* feedItem = qobject_cast<FeedItem*>(feedList->row(i));
76 24 : if (feedItem->isSpecialFeed() || feedItem->isFolder()) {
77 9 : continue;
78 : }
79 :
80 15 : qint64 parentId = feedItem->getParentFolderID();
81 15 : if (parentId > 0) {
82 6 : foldersWithChildren.insert(parentId);
83 : }
84 : }
85 :
86 : // Remove empty folders from the model (work backwards to avoid altering the index).
87 36 : for (int i = feedList->count() - 1; i >= 0; i--) {
88 24 : FolderFeedItem* folder = qobject_cast<FolderFeedItem*>(feedList->row(i));
89 24 : if (folder && !foldersWithChildren.contains(folder->getDbID())) {
90 4 : feedList->removeItem(folder);
91 4 : folderIDs.remove(folder->getDbID());
92 : }
93 : }
94 :
95 : // Delete orphaned folders from the database.
96 12 : QSqlQuery selectFolders(db());
97 12 : selectFolders.prepare("SELECT id FROM FeedItemTable WHERE is_folder = 1");
98 12 : if (selectFolders.exec()) {
99 22 : while (selectFolders.next()) {
100 10 : qint64 dbFolderId = selectFolders.value(0).toLongLong();
101 10 : if (!folderIDs.contains(dbFolderId)) {
102 6 : QSqlQuery deleteFolder(db());
103 6 : deleteFolder.prepare("DELETE FROM FeedItemTable WHERE id = :folder_id");
104 6 : deleteFolder.bindValue(":folder_id", dbFolderId);
105 6 : if (!deleteFolder.exec()) {
106 0 : reportSQLError(deleteFolder, "Unable to delete empty folder " + QString::number(dbFolderId));
107 : }
108 6 : }
109 : }
110 : }
111 :
112 : // Complete the DB transaction.
113 12 : db().commit();
114 :
115 : // Now we need to refresh our model. First up: ordinals.
116 32 : for (int i = 0; i < feedList->count(); i++) {
117 20 : FeedItem* feedItem = qobject_cast<FeedItem*>(feedList->row(i));
118 20 : if (feedItem->isSpecialFeed()) {
119 1 : continue;
120 : }
121 :
122 19 : feedItem->setOrdinal(i);
123 : }
124 :
125 : // Second: parent folders (or lack thereof.)
126 30 : for (FeedItem* item : removedFromFolder) {
127 18 : item->setParentFolder(-1);
128 : }
129 :
130 : // Recalculate unread counts for all folders; this handles the case where a feed
131 : // item is moved from one folder to another and both folders need to have their
132 : // feed counts updated.
133 32 : for (int i = 0; i < feedList->count(); i++) {
134 20 : FolderFeedItem* folder = qobject_cast<FolderFeedItem*>(feedList->row(i));
135 20 : if (folder) {
136 4 : UnreadCountReader::update(db(), folder);
137 : }
138 : }
139 12 : }
|