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