玉兔远程控制 0.1.0-bate8
载入中...
搜索中...
未找到
RecentDatabase.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QSettings>
4#include <QFile>
5#include <QFileInfo>
6#include <QIcon>
7#include <QSqlQuery>
8#include <QSqlError>
9#include <QDateTime>
10#include <QJsonArray>
11#include <QJsonObject>
12#include <QLoggingCategory>
13#include "RecentDatabase.h"
14#include "IconUtils.h"
15#include "RabbitCommonDir.h"
16
17static Q_LOGGING_CATEGORY(log, "App.Recent.Db")
18
19CRecentDatabase::RecentItem::RecentItem() : id(0) {
20}
21
22int CRecentDatabase::RecentItem::SetFile(const QString& file) {
23 szFile = CDatabaseFile::SetFile(file);
24 return 0;
25}
26
27QString CRecentDatabase::RecentItem::GetFile() {
28 return CDatabaseFile::GetFile(szFile);
29}
30
31CRecentDatabase::CRecentDatabase(QObject *parent)
32 : CDatabase{parent}
33{
34 qDebug(log) << Q_FUNC_INFO;
35}
36
37CRecentDatabase::~CRecentDatabase()
38{
39 qDebug(log) << Q_FUNC_INFO;
40}
41
43{
44 bool bRet = false;
46 if(!bRet) return false;
47
48 // Create icon table
49 bRet = m_IconDB.SetDatabase(GetDatabase(), m_pPara);
50 if(!bRet) return bRet;
51 bRet = m_FileDB.SetDatabase(GetDatabase(), m_pPara);
52 return bRet;
53}
54
55bool CRecentDatabase::OnInitializeSqliteDatabase()
56{
57 QSqlQuery query(GetDatabase());
58
59 // Create recent table
60 QString szSql =
61 "CREATE TABLE IF NOT EXISTS recent ("
62 " id INTEGER PRIMARY KEY AUTOINCREMENT,"
63 " operate_id TEXT NOT NULL,"
64 " icon INTEGER DEFAULT 0,"
65 " name TEXT NOT NULL,"
66 " protocol TEXT,"
67 " operate_type TEXT,"
68 " file TEXT UNIQUE NOT NULL,"
69 " time DATETIME DEFAULT CURRENT_TIMESTAMP,"
70 " description TEXT"
71 ")";
72 bool success = query.exec(szSql);
73
74 if (!success) {
75 SetError("Failed to create recent table: " + query.lastError().text()
76 + "; Sql:" + szSql);
77 qCritical(log) << GetError();
78 return false;
79 }
80
81 // Create index
82 success = query.exec("CREATE INDEX IF NOT EXISTS idx_recent_file ON recent(file)");
83 if(!success) {
84 qWarning(log) << "Failed to drop index idx_recent_file:"
85 << query.lastError().text()
86 << "Sql:" << query.executedQuery();
87 }
88
89 if (!query.exec("DROP TRIGGER IF EXISTS delete_icon_after_recent")) {
90 qDebug(log) << "Failed to drop trigger delete_icon_after_recent:"
91 << query.lastError().text()
92 << "Sql:" << query.executedQuery();
93 }
94
95 szSql = R"(
96 CREATE TRIGGER delete_icon_after_recent
97 AFTER DELETE ON recent
98 FOR EACH ROW
99 BEGIN
100 DELETE FROM icon
101 WHERE id = OLD.icon
102 AND OLD.icon != 0
103 AND NOT EXISTS (
104 SELECT 1 FROM favorite WHERE icon = OLD.icon
105 )
106 AND NOT EXISTS (
107 SELECT 1 FROM recent WHERE icon = OLD.icon
108 );
109 END;
110 )";
111 success = query.exec(szSql);
112 if (!success) {
113 qWarning(log) << "Failed to create trigger delete_icon_after_recent."
114 << query.lastError().text()
115 << "Sql:" << query.executedQuery();
116 }
117
118 return true;
119}
120
121bool CRecentDatabase::OnInitializeMySqlDatabase()
122{
123 bool success = false;
124 QSqlQuery query(GetDatabase());
125
126 // Create recent table
127 QString szSql =
128 "CREATE TABLE IF NOT EXISTS recent ("
129 " id INTEGER PRIMARY KEY AUTO_INCREMENT,"
130 " operate_id TEXT NOT NULL,"
131 " icon INTEGER DEFAULT 0,"
132 " name TEXT NOT NULL,"
133 " protocol TEXT,"
134 " operate_type TEXT,"
135 " file TEXT NOT NULL,"
136 " time DATETIME DEFAULT CURRENT_TIMESTAMP,"
137 " description TEXT,"
138 " UNIQUE KEY uk_recent_file (file(255))"
139 ")";
140 success = query.exec(szSql);
141 if (!success) {
142 SetError("Failed to create recent table: " + query.lastError().text()
143 + "; Sql: " + szSql);
144 qCritical(log) << GetError();
145 return false;
146 }
147
148 // Create trigger
149 if (!query.exec("DROP TRIGGER IF EXISTS delete_icon_after_recent")) {
150 qDebug(log) << "Failed to drop trigger delete_icon_after_recent:"
151 << query.lastError().text()
152 << "Sql:" << query.executedQuery();
153 }
154
155 szSql = R"(
156 CREATE TRIGGER delete_icon_after_recent
157 AFTER DELETE ON recent
158 FOR EACH ROW
159 BEGIN
160 DECLARE favorite_count INT DEFAULT 0;
161 DECLARE recent_count INT DEFAULT 0;
162
163 IF OLD.icon != 0 THEN
164 -- 统计favorite表中引用该icon的数量
165 SELECT COUNT(*) INTO favorite_count
166 FROM favorite
167 WHERE icon = OLD.icon;
168
169 -- 统计recent表中引用该icon的数量
170 SELECT COUNT(*) INTO recent_count
171 FROM recent
172 WHERE icon = OLD.icon;
173
174 -- 如果都没有引用,则删除icon
175 IF favorite_count = 0 AND recent_count = 0 THEN
176 DELETE FROM icon WHERE id = OLD.icon;
177 END IF;
178 END IF;
179 END
180 )";
181 success = query.exec(szSql);
182 if (!success) {
183 qWarning(log) << "Failed to create trigger delete_icon_after_recent."
184 << query.lastError().text()
185 << "Sql:" << query.executedQuery();
186 }
187
188 return true;
189}
190
191int CRecentDatabase::AddRecent(const RecentItem &item)
192{
193 QSqlQuery query(GetDatabase());
194 if(item.szFile.isEmpty())
195 return -1;
196 query.prepare(
197 "SELECT id FROM recent "
198 "WHERE file=:file"
199 );
200 query.bindValue(":file", item.szFile);
201 if (query.exec() && query.next()) {
202 // 更新现有记录
203 int id = query.value(0).toInt();
204
205 query.prepare(
206 "UPDATE recent SET "
207 "name=:name, "
208 "time=:time, "
209 "description=:description "
210 "WHERE id=:id"
211 );
212 query.bindValue(":name", item.szName);
213 query.bindValue(":time", item.time);
214 query.bindValue(":description", item.szDescription);
215 query.bindValue(":id", id);
216 } else {
217 query.prepare(
218 "INSERT INTO recent (operate_id, icon, name, protocol, operate_type, file, time, description)"
219 "VALUES (:operate_id, :icon, :name, :protocol, :type, :file, :time, :description)"
220 );
221 query.bindValue(":operate_id", item.szOperateId);
222 query.bindValue(":icon", m_IconDB.GetIcon(item.icon));
223 query.bindValue(":name", item.szName);
224 query.bindValue(":protocol", item.szProtocol);
225 query.bindValue(":type", item.szType);
226 query.bindValue(":file", item.szFile);
227 query.bindValue(":time", item.time);
228 query.bindValue(":description", item.szDescription);
229 }
230 bool success = query.exec();
231 if (!success) {
232 SetError("Failed to add recent: " + query.lastError().text()
233 + "; Sql: " + query.executedQuery());
234 qCritical(log) << GetError();
235 return 0;
236 }
237
238 qDebug(log) << "Insert recent id:" << query.lastInsertId().toInt();
239 emit sigChanged();
240 return query.lastInsertId().toInt();
241}
242
243bool CRecentDatabase::UpdateRecent(const RecentItem& item)
244{
245 return UpdateRecent(item.szFile, item.szName, item.szDescription);
246}
247
248bool CRecentDatabase::UpdateRecent(
249 const QString &szFile, const QString& szName, const QString& szDescription)
250{
251 QSqlQuery query(GetDatabase());
252
253 query.prepare(
254 "UPDATE recent SET "
255 "name=:name, "
256 "description=:description "
257 "WHERE file=:file"
258 );
259 query.bindValue(":name", szName);
260 query.bindValue(":file", szFile);
261 query.bindValue(":description", szDescription);
262
263 bool success = query.exec();
264 if (!success) {
265 SetError("Failed to update recent: " + query.lastError().text()
266 + "; Sql: " + query.executedQuery());
267 qCritical(log) << GetError();
268 }
269 emit sigChanged();
270 return success;
271}
272
273bool CRecentDatabase::DeleteRecent(int id)
274{
275 if(0 >= id) return false;
276 QSqlQuery query(GetDatabase());
277 query.prepare("DELETE FROM recent WHERE id=:id");
278 query.bindValue(":id", id);
279 bool success = query.exec();
280 if (!success) {
281 SetError("Failed to delete recent: " + query.lastError().text()
282 + "; Sql: " + query.executedQuery()
283 + "; id: " + QString::number(id));
284 qCritical(log) << GetError();
285 }
286 return success;
287}
288
289QList<CRecentDatabase::RecentItem> CRecentDatabase::GetRecents(int limit, int offset)
290{
291 QList<RecentItem> items;
292
293 QSqlQuery query(GetDatabase());
294 if(0 > limit) {
295 query.prepare(
296 "SELECT id, operate_id, icon, name, protocol, operate_type, file, time, description "
297 "FROM recent "
298 "ORDER BY time DESC "
299 );
300 } else {
301 query.prepare(
302 "SELECT id, operate_id, icon, name, protocol, operate_type, file, time, description "
303 "FROM recent "
304 "ORDER BY time DESC "
305 "LIMIT :limit OFFSET :offset"
306 );
307 query.bindValue(":limit", limit);
308 query.bindValue(":offset", offset);
309 }
310 if (query.exec()) {
311 while (query.next()) {
312 RecentItem item;
313 item.id = query.value(0).toInt();
314 item.szOperateId = query.value(1).toString();
315 item.icon = m_IconDB.GetIcon(query.value(2).toInt());
316 item.szName = query.value(3).toString();
317 item.szProtocol = query.value(4).toString();
318 item.szType = query.value(5).toString();
319 item.szFile = query.value(6).toString();
320 item.time = query.value(7).toDateTime();
321 item.szDescription = query.value(8).toString();
322 items.append(item);
323 }
324 } else {
325 SetError("Failed to get recents: " + query.lastError().text()
326 + "; Sql: " + query.executedQuery());
327 qCritical(log) << GetError();
328 }
329
330 return items;
331}
332
333bool CRecentDatabase::HasFileContents(const RecentItem &item)
334{
335 return m_FileDB.IsExist(item.szFile);
336}
337
338bool CRecentDatabase::ExportToJson(QJsonObject &obj)
339{
340 QJsonArray recents;
341 auto items = GetRecents();
342 foreach(auto it, items) {
343 QJsonObject itemObj;
344
345 bool bRet = CDatabaseFile::ExportFileToJson(it.GetFile(), itemObj);
346 if(!bRet) continue;
347
348 itemObj.insert("OperateId", it.szOperateId);
349
350 bRet = CDatabaseIcon::ExportIconToJson(it.icon, itemObj);
351 if(!bRet) continue;
352
353 itemObj.insert("Name", it.szName);
354 itemObj.insert("Protocol", it.szProtocol);
355 itemObj.insert("Type", it.szType);
356 itemObj.insert("Time", it.time.toString());
357 itemObj.insert("Description", it.szDescription);
358
359 recents.append(itemObj);
360 }
361 if(recents.isEmpty())
362 return false;
363 obj.insert("Recent", recents);
364 return true;
365}
366
367bool CRecentDatabase::ImportFromJson(const QJsonObject &obj)
368{
369 QJsonArray recents = obj["Recent"].toArray();
370 if(recents.isEmpty()){
371 SetError(tr("The file format is error. Don't find \"recents\""));
372 qCritical(log) << GetError();
373 return false;
374 }
375
376 for(auto it = recents.begin(); it != recents.end(); it++) {
377 QJsonObject itemObj = it->toObject();
378 RecentItem item;
379
380 QString szFile;
381 bool bRet = m_FileDB.ImportFileToDatabaseFromJson(itemObj, szFile);
382 if(!bRet) continue;
383
384 item.SetFile(szFile);
385 // Check if is exist in recent
386 QSqlQuery query(GetDatabase());
387 query.prepare(
388 "SELECT id FROM recent "
389 "WHERE file=:file"
390 );
391 query.bindValue(":file", item.szFile);
392 if (query.exec() && query.next()) {
393 continue;
394 }
395
396 bRet = CDatabaseIcon::ImportIconFromJson(itemObj, item.icon);
397 if(!bRet) continue;
398
399 item.szOperateId = itemObj["OperateId"].toString();
400 item.szName = itemObj["Name"].toString();
401 item.szProtocol = itemObj["Protocol"].toString();
402 item.szType = itemObj["Type"].toString();
403
404 item.time = QDateTime::fromString(itemObj["Time"].toString());
405 if(!item.time.isValid())
406 item.time = QDateTime::currentDateTime();
407
408 item.szDescription = itemObj["Description"].toString();
409 AddRecent(item);
410 }
411 return true;
412}
bool ImportFileToDatabaseFromJson(const QJsonObject &obj, QString &szFile)
Import file to database from JSON
Definition Database.cpp:715
static bool ExportFileToJson(const QString &szFile, QJsonObject &obj)
ExportFileToJson
Definition Database.cpp:657
static QString SetFile(const QString &szFile)
Set the file with file system to the file in database
Definition Database.cpp:892
static QString GetFile(const QString &szFile)
Get the file with file system from the file in database
Definition Database.cpp:881
int GetIcon(const QIcon &icon)
Get icon id
Definition Database.cpp:493
提供打开数据库和初始化数据库等接口
Definition Database.h:21
virtual bool OnInitializeDatabase()
Initialize database
Definition Database.cpp:288
bool SetDatabase(const CDatabase *db)
Share an existing database
Definition Database.cpp:34
The CRecentDatabase class
bool OnInitializeDatabase() override
Initialize database