Added skeletal implementation of ExternalExecutableModel.
[emufront] / src / db / dbmediaimagecontainer.cpp
1 // EmuFront
2 // Copyright 2010 Mikko Keinänen
3 //
4 // This file is part of EmuFront.
5 //
6 //
7 // EmuFront is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2 as published by
9 // the Free Software Foundation and appearing in the file gpl.txt included in the
10 // packaging of this file.
11 //
12 // EmuFront is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with EmuFront.  If not, see <http://www.gnu.org/licenses/>.
19
20 #include <QDebug>
21 #include <QSqlRecord>
22 #include <QSqlQuery>
23 #include <QSqlRelationalTableModel>
24 #include <QSqlError>
25 #include "dbmediaimagecontainer.h"
26 #include "dbmediaimage.h"
27 //#include "dbsetup.h"
28 #include "dbfilepath.h"
29
30 DbMediaImageContainer::DbMediaImageContainer(QObject *parent)
31     : DbFile(parent)
32 {
33     dbMediaImage = new DbMediaImage(parent);
34     dbFilePath = new DbFilePath(parent);
35     tableName = DbMediaImageContainer::DB_TABLE_MEDIAIMAGECONTAINER;
36 }
37
38 bool DbMediaImageContainer::updateDataObjectToModel(const EmuFrontObject *efo)
39 {
40     // TODO
41     return false;
42 }
43
44 /* Throws EmuFrontException */
45 int DbMediaImageContainer::storeMediaImageContainer(EmuFrontObject *efo)
46 {
47     MediaImageContainer *mic
48         = dynamic_cast<MediaImageContainer *>(efo);
49
50     if (!mic->getFilePath())
51         throw EmuFrontException("Cannot install media image "
52             "container to database without a file path object!");
53
54     // multiple media image containers with matching checksum will be stored
55     //       if each instance is in a different file path
56
57     int fileId = -1;
58     QMap<QString, EmuFrontObject*> images = mic->getMediaImages();
59     QList<int> ids = dbMediaImage->storeMediaImages(images);
60
61     //qDebug() << "Stored " << ids.count() << " media images.";
62
63     if (ids.count() <= 0)
64         return -1;
65
66     /* Contained Media images successfully stored to db,
67         storing media image container also */
68
69     try {
70
71         // Insert MediaImageContainer first as a EmuFrontFile object to file table.
72
73         // File id is used to store the media image container instance to database,
74         // file id is also the media image container id
75
76         // TODO: if this fails, the remove the media images in ids
77         fileId = insertDataObjectToModel(mic);
78
79         //qDebug() << "Inserted media image container to file table with id " << fileId << ".";
80
81         if (fileId < 0) {
82             // TODO: note we most surely need to catch the exception
83             // in the calling code block and clean
84             // all the media image and ...containers from
85             // the memory!
86             throw EmuFrontException(
87                     QString(tr("Inserting media image container %1 to file database failed"))
88                     .arg(mic->getName()));
89         }
90
91         mic->setId(fileId);
92
93         if (!linkMediaImageContainerToPath(mic)){
94             DbFile::deleteDataObject(fileId);
95             throw EmuFrontException("Failed inserting media image to database!");
96         }
97         //qDebug() << "Inserted media image container " << fileId << " to mediaimagecontainer table.";
98         linkMediaImagesWithContainer(fileId, images.values());
99         //qDebug() << "Linked media image container with media images.";
100     } catch (EmuFrontException e) {
101         dbMediaImage->removeOrphanedMediaImages(ids);
102         throw e;
103     }
104
105     return fileId;
106 }
107
108 bool DbMediaImageContainer::deleteDataObjectFromModel(QModelIndex *i)
109 {
110     // TODO
111     return false;
112 }
113
114 QString DbMediaImageContainer::constructSelect(QString whereClause) const
115 {
116     // TODO, for a usual search we need a "light" version of this select
117     // and MediaImageContainer (only id, name)
118     QString select = QString("SELECT file.id, file.name, file.checksum, file.size, "
119                 "        filepath.id, filepath.name, "
120                 "        setup.id, "
121                 "        platform.id, platform.name, "
122                 "        mediatype.id, mediatype.name "
123                 "FROM file "
124                 "INNER JOIN mediaimagecontainer_filepath ON mediaimagecontainer_filepath.fileid = file.id "
125                 "INNER JOIN filepath ON mediaimagecontainer_filepath.filepathid = filepath.id "
126                 "INNER JOIN setup ON filepath.setupid = setup.id "
127                 "INNER JOIN platform ON setup.platformid = platform.id "
128                 "INNER JOIN mediatype ON setup.mediatypeid = mediatype.id "
129                 "%1 "
130                 "ORDER BY file.name").arg(whereClause);
131     //qDebug() << select;
132     return select;
133 }
134
135 QString DbMediaImageContainer::constructFilterById(int id) const
136 {
137     return QString("file.id = %1").arg(id);
138 }
139
140 QString DbMediaImageContainer::constructSelectById(int id) const
141 {
142     return constructSelect(
143         QString("WHERE %1").arg(constructFilterById(id))
144         );
145 }
146
147 /* Throws EmuFrontException */
148 EmuFrontObject* DbMediaImageContainer::recordToDataObject(const QSqlRecord *rec)
149 {
150     // TODO: checks!
151     MediaImageContainer *mic = 0;
152     if (!rec) return mic;
153     int id = rec->value(MIC_FileId).toInt();
154     QString name = rec->value(MIC_FileName).toString();
155     QString checksum = rec->value(MIC_FileCheckSum).toString();
156     int size = rec->value(MIC_FileSize).toInt();
157     int fpId = rec->value(MIC_FilePathId).toInt();
158     FilePathObject *fpo
159         = dynamic_cast<FilePathObject*>(dbFilePath->getDataObject(fpId)); /* Throws EmuFrontException */
160     //int supId = rec->value(MIC_SetupId).toInt();
161     //Setup *sup = dbSetup->getDataObject(supId)
162     QMap<QString, EmuFrontObject*> images = dbMediaImage->getMediaImages(id);
163
164     mic = new MediaImageContainer(
165        id, name, checksum, size, images, fpo
166     );
167     return mic;
168 }
169
170 QSqlQueryModel* DbMediaImageContainer::getData()
171 {
172     QSqlQueryModel *model = new QSqlQueryModel(this);
173     if (sqlTableModel){
174         model->setQuery(sqlTableModel->query());
175     }
176     else
177         model->setQuery(constructSelect());
178     model->setHeaderData(MIC_FileId, Qt::Horizontal, tr("File id"));
179     model->setHeaderData(MIC_FileName, Qt::Horizontal, tr("File Name"));
180     model->setHeaderData(MIC_FileCheckSum, Qt::Horizontal, tr("File checksum"));
181     model->setHeaderData(MIC_FileSize, Qt::Horizontal, tr("File Size"));
182     model->setHeaderData(MIC_FilePathId, Qt::Horizontal, tr("File path id"));
183     model->setHeaderData(MIC_FilePathName, Qt::Horizontal, tr("File path name"));
184     model->setHeaderData(MIC_SetupId, Qt::Horizontal, tr("Setup id"));
185     model->setHeaderData(MIC_PlatformId, Qt::Horizontal, tr("Platform id"));
186     model->setHeaderData(MIC_PlatformName, Qt::Horizontal, tr("Platform name"));
187     model->setHeaderData(MIC_MediaTypeId, Qt::Horizontal, tr("Media type id"));
188     model->setHeaderData(MIC_MediaTypeName, Qt::Horizontal, tr("Media type name"));
189     return model;
190 }
191
192 /* Returns the id of a media image container with a given cheksum or -1 if not found */
193 int DbMediaImageContainer::getMediaImageContainer(QString checksum) const
194 {
195     QSqlQuery q;
196     q.prepare("SELECT id FROM file WHERE checksum=:checksum");
197     q.bindValue(":checksum", checksum);
198     int id = -1;
199     if (q.next())
200         id = q.value(0).toInt();
201     return id;
202 }
203
204
205 /**
206 * Stores media image containers, including the media images included
207 * to database.
208 *
209 * Throws EmuFrontException
210 */
211 void DbMediaImageContainer::storeContainers(QList<MediaImageContainer *> lst, FilePathObject *fpo)
212 {
213     foreach(MediaImageContainer *mic, lst)
214     {
215         //qDebug() << "Media image container " << mic->getName();
216         int micFileId = storeMediaImageContainer(mic);
217     }
218 }
219
220 /* Throws EmuFrontException */
221 void DbMediaImageContainer::linkMediaImagesWithContainer(int micId, QList<EmuFrontObject*> mediaImages)
222 {
223     if (micId < 0 || mediaImages.count() <= 0)
224         return;
225
226     MediaImage *mi = 0;
227     foreach(EmuFrontObject *efo, mediaImages) {
228         mi = dynamic_cast<MediaImage*>(efo);
229         /*qDebug() << "Linking media image container " << micId
230             << " to media image " << mi->getId()  << ", " << mi->getName() << ".";*/
231         if (!linkMediaImageToMediaImageContainer(mi, micId)) {
232                 throw EmuFrontException(QString("Failed linking media "
233                                                     "image container %1 to a media image %2").arg(micId).arg(mi->getId()));
234         }
235     }
236 }
237
238 void DbMediaImageContainer::filter(int mediaTypeId, int platformId)
239 {
240     /*qDebug() << "Filtering media images with media type " << mediaTypeId
241         << " and platform " << platformId;*/
242     QList<QString> filters;
243     if (mediaTypeId >= 0)
244         filters.append(QString("mediatype.id=%1").arg(mediaTypeId));
245     if (platformId >= 0)
246         filters.append(QString("platform.id=%1").arg(platformId));
247     filterDataObjects(filters);
248 }
249
250 QString DbMediaImageContainer::getCountRefsSelect(int id) const
251 {
252     /* we need to count file references to give media image container */
253     /* example:
254         select count(*) from mediaimagecontainer
255         INNER JOIN mediaimagecontainer_mediaimage
256         ON mediaimagecontainer_mediaimage.mediaimagecontainerid
257         = mediaimagecontainer.fileid
258         WHERE mediaimagecontainer.fileid=589;
259     */
260     return QString("SELECT count(*) FROM mediaimagecontainer "
261               "INNER JOIN mediaimagecontainer_mediaimage "
262               "ON mediaimagecontainer_mediaimage.mediaimagecontainerid "
263               "    =mediaimagecontainer.fileid "
264               "WHERE mediaimagecontainer.fileid=%1").arg(id);
265 }
266
267 QString DbMediaImageContainer::getDeleteObjectSql() const
268 {
269        // The trigger will take care of deleting
270        // the reference from the mediaimagecontainer
271        // and mediaimage_mediaimagecontainer tables.
272        // there is also a trigger that will delete
273        // all the files linked to mediaimagecontainer
274        // using mediaimage_mediaimagecontainer (the actual
275        // mediaimages).
276        return QString("DELETE FROM file WHERE id=:id");
277 }
278
279 /* Throws EmuFrontException */
280 EmuFrontObject* DbMediaImageContainer::getMediaImageContainerByChecksum(QString checksum)
281 {
282     return getDataObject(QString("file.checksum LIKE '%1'").arg(checksum));
283 }
284
285 bool DbMediaImageContainer::linkMediaImageContainerToPath(const MediaImageContainer *mic) const
286 {
287     QSqlQuery q;
288     q.prepare("INSERT INTO mediaimagecontainer_filepath "
289               "(fileid, filepathid, updatetime) "
290               "VALUES (:fileid, :filepathid, :updatetime)");
291     q.bindValue(":fileid", mic->getId());
292     q.bindValue(":filepathid", mic->getFilePath()->getId());
293     q.bindValue(":updatetime", DatabaseManager::getCurrentTimeStamp());
294     return q.exec();
295 }
296
297 bool DbMediaImageContainer::linkMediaImageToMediaImageContainer(const MediaImage *mi, int micId) const
298 {
299     QSqlQuery q;
300     q.prepare("INSERT INTO mediaimagecontainer_mediaimage "
301         "(mediaimagecontainerid, mediaimageid) "
302         "VALUES (:micid, :miid) ");
303     q.bindValue(":micid", micId);
304     q.bindValue(":miid", mi->getId());
305     return q.exec();
306 }
307
308 bool DbMediaImageContainer::removeFromFilePath(int filePathId) const
309 {
310     QSqlQuery q;
311     q.prepare("DELETE FROM mediaimagecontainer_filepath "
312         "WHERE filepathid=:filepathid");
313     q.bindValue(":filepathid", filePathId);
314     return q.exec();
315 }