MediaImageContainer presents contained media images in a map instead of
[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
31 DbMediaImageContainer::DbMediaImageContainer(QObject *parent)
32     : DbFile(parent) // DbQueryModelManager(parent)
33 {
34     dbMediaImage = new DbMediaImage(parent);
35     dbFilePath = new DbFilePath(parent);
36     tableName = DbMediaImageContainer::DB_TABLE_MEDIAIMAGECONTAINER;
37     //dbFile = new DbFile(parent);
38 }
39
40 bool DbMediaImageContainer::updateDataObjectToModel(const EmuFrontObject *efo)
41 {
42     // TODO
43     return false;
44 }
45
46 int DbMediaImageContainer::insertDataObjectToModel(const EmuFrontObject *efo)
47 {
48     const MediaImageContainer *mic
49         = dynamic_cast<const MediaImageContainer *>(efo);
50
51     // check if this media image container is already in the database
52     EmuFrontObject *o = getFileByChecksum(mic->getCheckSum());
53     int fileId = o ? o->getId() : -1;
54     /*int fileId = getMediaImageContainer(mic->getCheckSum());*/
55     if (fileId >= 0) {
56         qDebug() << "Media image container already in db with id " << fileId << ".";
57         return fileId;
58    }
59
60     if (!mic->getFilePath())
61         throw new EmuFrontException("Cannot install media image "
62             "container to database without a file path object!");
63
64     QMap<QString, EmuFrontObject*> images = mic->getMediaImages();
65     QList<int> ids = dbMediaImage->storeMediaImages(images);
66
67     qDebug() << "Stored " << ids.count() << " media images.";
68
69     if (ids.count() <= 0)
70         return -1;
71
72     /* Contained Media images successfully stored to db,
73         storing media image container also */
74
75     try {
76
77         // Insert MediaImageContainer first as a EmuFrontFile object to file table.
78
79         // File id is used to store the media image container instance to database,
80         // file id is also the media image container id
81         fileId = DbFile::insertDataObjectToModel(mic);
82
83         qDebug() << "Inserted media image container to file table with id " << fileId << ".";
84
85         if (fileId < 0) {
86             // TODO: note we most surely need to catch the exception
87             // in the calling code block and clean
88             // all the media image and ...containers from
89             // the memory!
90             throw new EmuFrontException(
91                     QString(tr("Inserting media image container %1 to file database failed"))
92                     .arg(mic->getName()));
93         }
94
95         // Insert to mediaimagecontainer table
96
97         QSqlQuery q;
98         q.prepare("INSERT INTO mediaimagecontainer "
99                   "(fileid, filepathid, updatetime) "
100                   "VALUES (:fileid, :filepathid, :updatetime)");
101         q.bindValue(":fileid", fileId);
102         q.bindValue(":filepathid", mic->getFilePath()->getId());
103         q.bindValue(":updatetime", DatabaseManager::getCurrentTimeStamp());
104         if (!q.exec()){
105             DbFile::deleteDataObject(fileId);
106             throw new EmuFrontException("Failed inserting media image to database!");
107         }
108         qDebug() << "Inserted media image container " << fileId << " to mediaimagecontainer table.";
109         linkMediaImagesWithContainer(fileId, ids);
110         qDebug() << "Linked media image container with media images.";
111     } catch (EmuFrontException e) {
112         dbMediaImage->removeOrphanedMediaImages(ids);
113         throw e;
114     }
115
116     return fileId;
117 }
118
119 bool DbMediaImageContainer::deleteDataObjectFromModel(QModelIndex *i)
120 {
121     // TODO
122     return false;
123 }
124
125 QString DbMediaImageContainer::constructSelect(QString whereClause) const
126 {
127     // TODO, for a usual search we need a "light" version of this select
128     // and MediaImageContainer (only id, name)
129     QString select = QString("SELECT file.id, file.name, file.checksum, file.size, "
130                 "        filepath.id, filepath.name, "
131                 "        setup.id, "
132                 "        platform.id, platform.name, "
133                 "        mediatype.id, mediatype.name "
134                 "FROM mediaimagecontainer "
135                 "INNER JOIN file ON mediaimagecontainer.fileid = file.id "
136                 "INNER JOIN filepath ON mediaimagecontainer.filepathid = filepath.id "
137                 "INNER JOIN setup ON filepath.setupid = setup.id "
138                 "INNER JOIN platform ON setup.platformid = platform.id "
139                 "INNER JOIN mediatype ON setup.mediatypeid = mediatype.id "
140                 "%1 "
141                 "ORDER BY file.name").arg(whereClause);
142     qDebug() << select;
143     return select;
144 }
145
146 QString DbMediaImageContainer::constructFilterById(int id) const
147 {
148     return QString("file.id = %1").arg(id);
149 }
150
151 QString DbMediaImageContainer::constructSelectById(int id) const
152 {
153     return constructSelect(
154         QString("WHERE %1").arg(constructFilterById(id))
155         );
156 }
157
158 EmuFrontObject* DbMediaImageContainer::recordToDataObject(const QSqlRecord *rec)
159 {
160     // TODO: checks!
161     MediaImageContainer *mic = 0;
162     if (!rec) return mic;
163     int id = rec->value(MIC_FileId).toInt();
164     QString name = rec->value(MIC_FileName).toString();
165     QString checksum = rec->value(MIC_FileCheckSum).toString();
166     int size = rec->value(MIC_FileSize).toInt();
167     int fpId = rec->value(MIC_FilePathId).toInt();
168     FilePathObject *fpo
169         = dynamic_cast<FilePathObject*>(dbFilePath->getDataObject(fpId));
170     //int supId = rec->value(MIC_SetupId).toInt();
171     //Setup *sup = dbSetup->getDataObject(supId)
172     QMap<QString, EmuFrontObject*> images = dbMediaImage->getMediaImages(id);
173
174     mic = new MediaImageContainer(
175        id, name, checksum, size, images, fpo
176     );
177     return mic;
178 }
179
180 QSqlQueryModel* DbMediaImageContainer::getData()
181 {
182     QSqlQueryModel *model = new QSqlQueryModel(this);
183     if (sqlTableModel){
184         model->setQuery(sqlTableModel->query());
185     }
186     else
187         model->setQuery(constructSelect());
188     model->setHeaderData(MIC_FileId, Qt::Horizontal, tr("File id"));
189     model->setHeaderData(MIC_FileName, Qt::Horizontal, tr("File Name"));
190     model->setHeaderData(MIC_FileCheckSum, Qt::Horizontal, tr("File checksum"));
191     model->setHeaderData(MIC_FileSize, Qt::Horizontal, tr("File Size"));
192     model->setHeaderData(MIC_FilePathId, Qt::Horizontal, tr("File path id"));
193     model->setHeaderData(MIC_FilePathName, Qt::Horizontal, tr("File path name"));
194     model->setHeaderData(MIC_SetupId, Qt::Horizontal, tr("Setup id"));
195     model->setHeaderData(MIC_PlatformId, Qt::Horizontal, tr("Platform id"));
196     model->setHeaderData(MIC_PlatformName, Qt::Horizontal, tr("Platform name"));
197     model->setHeaderData(MIC_MediaTypeId, Qt::Horizontal, tr("Media type id"));
198     model->setHeaderData(MIC_MediaTypeName, Qt::Horizontal, tr("Media type name"));
199     return model;
200 }
201
202 /* Returns the id of a media image container with a given cheksum or -1 if not found */
203 int DbMediaImageContainer::getMediaImageContainer(QString checksum) const
204 {
205     QSqlQuery q;
206     q.prepare("SELECT id FROM file WHERE checksum=:checksum");
207     q.bindValue(":checksum", checksum);
208     int id = -1;
209     if (q.next())
210         id = q.value(0).toInt();
211     return id;
212 }
213
214
215 /**
216 * Stores media image containers, including the media images included
217 * to database.
218 */
219 void DbMediaImageContainer::storeContainers(QList<MediaImageContainer *> lst, FilePathObject *fpo)
220 {
221     qDebug() << "Storing media image containers to database.";
222     foreach(MediaImageContainer *mic, lst)
223     {
224         qDebug() << "Media image container " << mic->getName();
225         int micFileId = insertDataObjectToModel(mic);
226     }
227 }
228
229 void DbMediaImageContainer::linkMediaImagesWithContainer(int micId, QList<int> miIds)
230 {
231     if (micId < 0 || miIds.count() <= 0)
232         return;
233
234     QSqlQuery q;
235     q.prepare("INSERT INTO mediaimagecontainer_mediaimage "
236         "(mediaimagecontainerid, mediaimageid) "
237         "VALUES (:micid, :miid) ");
238     q.bindValue(":micid", micId);
239
240     foreach(int miid, miIds) {
241         qDebug() << "Linking media image container " << micId << " to media image " << miid  << ".";
242         q.bindValue(":miid", miid);
243         if (!q.exec()) {
244             throw new EmuFrontException(QString("Failed linking media "
245                 "image container %1 to a media image %2").arg(micId).arg(miid));
246         }
247     }
248 }
249
250 void DbMediaImageContainer::filter(int mediaTypeId, int platformId)
251 {
252     qDebug() << "Filtering media images with media type " << mediaTypeId
253         << " and platform " << platformId;
254     QList<QString> filters;
255     if (mediaTypeId >= 0)
256         filters.append(QString("mediatype.id=%1").arg(mediaTypeId));
257     if (platformId >= 0)
258         filters.append(QString("platform.id=%1").arg(platformId));
259     filterDataObjects(filters);
260 }
261
262 QString DbMediaImageContainer::getCountRefsSelect(int id) const
263 {
264     /* we need to count file references to give media image container */
265     /* example:
266         select count(*) from mediaimagecontainer
267         INNER JOIN mediaimagecontainer_mediaimage
268         ON mediaimagecontainer_mediaimage.mediaimagecontainerid
269         = mediaimagecontainer.fileid
270         WHERE mediaimagecontainer.fileid=589;
271     */
272     return QString("SELECT count(*) FROM mediaimagecontainer "
273               "INNER JOIN mediaimagecontainer_mediaimage "
274               "ON mediaimagecontainer_mediaimage.mediaimagecontainerid "
275               "    =mediaimagecontainer.fileid "
276               "WHERE mediaimagecontainer.fileid=%1").arg(id);
277 }
278
279 QString DbMediaImageContainer::getDeleteObjectSql() const
280 {
281        // The trigger will take care of deleting
282        // the reference from the mediaimagecontainer
283        // and mediaimage_mediaimagecontainer tables.
284        // there is also a trigger that will delete
285        // all the files linked to mediaimagecontainer
286        // using mediaimage_mediaimagecontainer (the actual
287        // mediaimages).
288        return QString("DELETE FROM file WHERE id=:id");
289 }