1 #include "folder_query_result_processor.h"
2
3 #include "folder_item.h"
4 #include "qnaturalsorting.h"
5 #include "yacreader_global_gui.h"
6 #include "query_parser.h"
7 #include "folder_model.h"
8 #include "data_base_management.h"
9
10 #include "QsLog.h"
11
12 #include <QSqlQuery>
13 #include <QSqlDatabase>
14
15 //Copy/pasted from "folder_model.cpp"
16 #define ROOT 1
17
FolderQueryResultProcessor(FolderModel * model)18 YACReader::FolderQueryResultProcessor::FolderQueryResultProcessor(FolderModel *model)
19 : querySearchQueue(1), model(model)
20 {
21 }
22
createModelData(const YACReader::SearchModifiers modifier,const QString & filter,bool includeComics)23 void YACReader::FolderQueryResultProcessor::createModelData(const YACReader::SearchModifiers modifier, const QString &filter, bool includeComics)
24 {
25 querySearchQueue.cancellPending();
26
27 querySearchQueue.enqueue([=] {
28 QString connectionName = "";
29 {
30 QSqlDatabase db = DataBaseManagement::loadDatabase(model->getDatabase());
31
32 QSqlQuery selectQuery(db); //TODO check
33 if (!includeComics) {
34 selectQuery.prepare("select * from folder where id <> 1 and upper(name) like upper(:filter) order by parentId,name ");
35 selectQuery.bindValue(":filter", "%%" + filter + "%%");
36 } else {
37 std::string queryString("SELECT DISTINCT f.id, f.parentId, f.name, f.path, f.finished, f.completed "
38 "FROM folder f LEFT JOIN comic c ON (f.id = c.parentId) "
39 "INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) WHERE ");
40
41 try {
42 QueryParser parser;
43 auto result = parser.parse(filter.toStdString());
44 result.buildSqlString(queryString);
45
46 switch (modifier) {
47 case YACReader::NoModifiers:
48 queryString += " AND f.id <> 1 ORDER BY f.parentId,f.name";
49 break;
50
51 case YACReader::OnlyRead:
52 queryString += " AND f.id <> 1 AND ci.read = 1 ORDER BY f.parentId,f.name";
53 break;
54
55 case YACReader::OnlyUnread:
56 queryString += " AND f.id <> 1 AND ci.read = 0 ORDER BY f.parentId,f.name";
57 break;
58
59 default:
60 queryString += " AND f.id <> 1 ORDER BY f.parentId,f.name";
61 QLOG_ERROR() << "not implemented";
62 break;
63 }
64
65 selectQuery.prepare(queryString.c_str());
66 result.bindValues(selectQuery);
67
68 selectQuery.exec();
69 QLOG_DEBUG() << selectQuery.lastError() << "--";
70
71 setupFilteredModelData(selectQuery);
72 } catch (const std::exception &e) {
73 //Do nothing, uncomplete search string will end here and it is part of how the QueryParser works
74 //I don't like the idea of using exceptions for this though
75 }
76 }
77
78 connectionName = db.connectionName();
79 }
80
81 QSqlDatabase::removeDatabase(connectionName);
82 });
83 }
84
setupFilteredModelData(QSqlQuery & sqlquery)85 void YACReader::FolderQueryResultProcessor::setupFilteredModelData(QSqlQuery &sqlquery)
86 {
87 FolderItem *rootItem = 0;
88
89 //inicializar el nodo ra�z
90 QList<QVariant> rootData;
91 rootData << "root";
92 rootItem = new FolderItem(rootData);
93 rootItem->id = ROOT;
94 rootItem->parentItem = 0;
95
96 FolderItem *parent = rootItem;
97
98 QMap<unsigned long long int, FolderItem *> *filteredItems = new QMap<unsigned long long int, FolderItem *>();
99
100 //add tree root node
101 filteredItems->insert(parent->id, parent);
102
103 QSqlRecord record = sqlquery.record();
104
105 int name = record.indexOf("name");
106 int path = record.indexOf("path");
107 int finished = record.indexOf("finished");
108 int completed = record.indexOf("completed");
109 int parentIdIndex = record.indexOf("parentId");
110
111 while (sqlquery.next()) { //se procesan todos los folders que cumplen con el filtro
112 //datos de la base de datos
113 QList<QVariant> data;
114
115 data << sqlquery.value(name).toString();
116 data << sqlquery.value(path).toString();
117 data << sqlquery.value(finished).toBool();
118 data << sqlquery.value(completed).toBool();
119
120 auto item = new FolderItem(data);
121 item->id = sqlquery.value(0).toULongLong();
122
123 //id del padre
124 quint64 parentId = sqlquery.value(parentIdIndex).toULongLong();
125
126 //se a�ade el item al map, de forma que se pueda encontrar como padre en siguientes iteraciones
127 if (!filteredItems->contains(item->id))
128 filteredItems->insert(item->id, item);
129
130 //es necesario conocer las coordenadas de origen para poder realizar scroll autom�tico en la vista
131 item->originalItem = model->items.value(item->id);
132
133 //si el padre ya existe en el modelo, el item se a�ade como hijo
134 if (filteredItems->contains(parentId))
135 filteredItems->value(parentId)->appendChild(item);
136 else //si el padre a�n no se ha a�adido, hay que a�adirlo a �l y todos los padres hasta el nodo ra�z
137 {
138 //comprobamos con esta variable si el �ltimo de los padres (antes del nodo ra�z) ya exist�a en el modelo
139 bool parentPreviousInserted = false;
140
141 //mientras no se alcance el nodo ra�z se procesan todos los padres (de abajo a arriba)
142 while (parentId != ROOT) {
143 //el padre no estaba en el modelo filtrado, as� que se rescata del modelo original
144 FolderItem *parentItem = model->items.value(parentId);
145 //se debe crear un nuevo nodo (para no compartir los hijos con el nodo original)
146 FolderItem *newparentItem = new FolderItem(parentItem->getData()); //padre que se a�adir� a la estructura de directorios filtrados
147 newparentItem->id = parentId;
148
149 newparentItem->originalItem = parentItem;
150
151 //si el modelo contiene al padre, se a�ade el item actual como hijo
152 if (filteredItems->contains(parentId)) {
153 filteredItems->value(parentId)->appendChild(item);
154 parentPreviousInserted = true;
155 }
156 //sino se registra el nodo para poder encontrarlo con posterioridad y se a�ade el item actual como hijo
157 else {
158 newparentItem->appendChild(item);
159 filteredItems->insert(newparentItem->id, newparentItem);
160 parentPreviousInserted = false;
161 }
162
163 //variables de control del bucle, se avanza hacia el nodo padre
164 item = newparentItem;
165 parentId = parentItem->parentItem->id;
166 }
167
168 //si el nodo es hijo de 1 y no hab�a sido previamente insertado como hijo, se a�ade como tal
169 if (!parentPreviousInserted) {
170 filteredItems->value(ROOT)->appendChild(item);
171 } else {
172 delete item;
173 }
174 }
175 }
176
177 emit newData(filteredItems, rootItem);
178 }
179