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