Imported needed functionality from (soon) deprecated database
[emufront] / src / models / externalexecutablemodel.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
22 #include "externalexecutablemodel.h"
23 #include "executable.h"
24 #include "setup.h"
25 #include "setupmodel.h"
26 #include "emufrontexception.h"
27 #include <QtSql>
28
29 ExternalExecutableModel::ExternalExecutableModel(QObject *parent) :
30     EmuFrontQueryModel(parent)
31 {
32     editableColumns << Executable_Name;
33     editableColumns << Executable_Options;
34     editableColumns << Executable_Executable;
35     editableColumns << Executable_SetupId;
36     refresh();
37 }
38
39 void ExternalExecutableModel::refresh()
40 {
41     setQuery(constructSelect());
42     setHeaderData(Executable_Id, Qt::Horizontal, tr("Id"));
43     setHeaderData(Executable_Name, Qt::Horizontal, tr("Name"));
44     setHeaderData(Executable_Executable, Qt::Horizontal, tr("Executable"));
45     setHeaderData(Executable_Options, Qt::Horizontal, tr("Options"));
46     setHeaderData(Executable_TypeId, Qt::Horizontal, tr("Type"));
47     setHeaderData(Executable_SetupId, Qt::Horizontal, tr("Setup id"));
48     setHeaderData(Executable_SetupName, Qt::Horizontal, tr("Setup"));
49 }
50
51 QString ExternalExecutableModel::constructSelect(QString where) const
52 {
53     return QString("SELECT "
54                    "executable.id AS ExecutableId, "
55                    "executable.name AS ExecutableName, "
56                    "executable.executable AS Executable, "
57                    "executable.options AS ExecutableOptions, "
58                    "executable.type AS ExecutableType, "
59                    "setup.id As ExecutableSetupId, "
60                    "platform.name || ' ' || mediatype.name AS SetupName "
61                    "FROM executable "
62                    "INNER JOIN setup ON executable.setupid = setup.id "
63                    "INNER JOIN platform ON setup.platformid=platform.id "
64                    "INNER JOIN mediatype ON setup.mediatypeid=mediatype.id "
65                    " %1 "
66                    "ORDER BY executable.name").arg(where);
67 }
68
69 Qt::ItemFlags ExternalExecutableModel::flags(const QModelIndex &index) const
70 {
71     Qt::ItemFlags flags = QSqlQueryModel::flags(index);
72     int col = index.column();
73     if (editableColumns.contains(index.column())) {
74        flags  |= Qt::ItemIsEditable;
75     }
76     return flags;
77 }
78
79 bool ExternalExecutableModel::setData(const QModelIndex &index, const QVariant &value, int role)
80 {
81     if (!editableColumns.contains(index.column()))
82         return false;
83
84     QModelIndex primaryKeyIndex = QSqlQueryModel::index(index.row(), Executable_Id);
85     int id = data(primaryKeyIndex).toInt();
86     clear();
87     bool ok;
88     switch(index.column())
89     {
90         case Executable_Name:
91             ok = setExecutableName(id, value.toString());
92             break;
93         case Executable_Executable:
94             ok = setExecutable(id, value.toString());
95             break;
96         case Executable_Options:
97             ok = setOptions(id, value.toString());
98             break;
99         case Executable_SetupId:
100             ok = setSetup(id, value.toInt());
101             break;
102         default:
103             ok = false;
104     }
105     refresh();
106     return ok;
107 }
108
109 bool ExternalExecutableModel::insertRows(int row, int count, const QModelIndex &parent)
110 {
111     if (parent.isValid())
112         return false; // This is a flat model
113     if (rowCount() < row)
114         row = rowCount() + 1;
115
116     // Fetch a setup for an initial selection
117     int supId = -1;
118     QSqlQuery q;
119     q.exec(QString("SELECT setup.id, "
120            // The following is to get the correct order:
121            "platform.name || ' ' || mediatype.name AS SetupName "
122            "FROM setup "
123            "INNER JOIN platform ON setup.platformid=platform.id "
124            "INNER JOIN mediatype ON setup.mediatypeid=mediatype.id "
125            "ORDER BY SetupName "
126            "LIMIT 1"));
127     if (q.first()) {
128         supId = q.value(0).toInt();
129         qDebug() << "Got id " << supId << " for default setup.";
130     }
131     else {
132         throw EmuFrontException(tr("No setups yet available for file path configuration!"));
133     }
134     q.prepare(QString("INSERT INTO executable "
135         "(id, name, executable, options, type, setupid) "
136         "VALUES (NULL, '', '', '', :type, :supid)"
137     ));
138     beginInsertRows(QModelIndex(), row, row + count - 1);
139     for(int i = 0; i < count; ++i) {
140         q.bindValue(":supid", supId);
141         q.bindValue(":type", Executable::ExecutableType_Emulator);
142         if (!q.exec()) {
143             throw EmuFrontException(tr("Failed creating new external executable row: %1").
144                                     arg(q.lastError().text()));
145         }
146     }
147     endInsertRows();
148     refresh();
149     return true;
150 }
151
152 bool ExternalExecutableModel::removeRows(int row, int count, const QModelIndex &parent)
153 {
154     if (parent.isValid()) {
155         return false; // This is a flat model
156     }
157     if (rowCount() < row + count - 1)
158         return false;
159
160     QSqlQuery q;
161     q.prepare(QString("DELETE FROM executable WHERE id=:id"));
162     QModelIndex primaryIndex;
163     int id = -1;
164     beginRemoveRows(QModelIndex(), row, row + count - 1);
165     for(int i = 0; i < count; ++i) {
166         primaryIndex = QSqlQueryModel::index(row + i, Executable_Id);
167         id = data(primaryIndex).toInt();
168         qDebug() << "Removing data item with id " << id;
169         q.bindValue(":id", id);
170         q.exec();
171     }
172     endRemoveRows();
173     refresh();
174     return true;
175 }
176
177 bool ExternalExecutableModel::setSetup(int id, int setupId)
178 {
179     QSqlQuery q;
180     q.prepare(QString("UPDATE executable SET setupid = :supid WHERE id = :id"));
181     q.bindValue(":supid", setupId);
182     q.bindValue(":id", id);
183     return q.exec();
184 }
185
186 bool ExternalExecutableModel::setExecutable(int id, QString name)
187 {
188     QSqlQuery q;
189     q.prepare(QString("UPDATE executable SET executable = :exec WHERE id = :id"));
190     q.bindValue(":exec", name);
191     q.bindValue(":id", id);
192     return q.exec();
193 }
194
195 bool ExternalExecutableModel::setOptions(int id, QString options)
196 {
197     QSqlQuery q;
198     q.prepare(QString("UPDATE executable SET options = :opts WHERE id = :id"));
199     q.bindValue(":opts", options);
200     q.bindValue(":id", id);
201     return q.exec();
202 }
203
204 bool ExternalExecutableModel::setExecutableName(int id, QString name)
205 {
206     QSqlQuery q;
207     q.prepare(QString("UPDATE executable SET name = :name WHERE id = :id"));
208     q.bindValue(":name", name);
209     q.bindValue(":id", id);
210     return q.exec();
211 }
212
213 void ExternalExecutableModel::filterBySetup(int setupid)
214 {
215     QList<QString> filters;
216     filters.append(QString("executable.setupid=%1").arg(setupid));
217     filterDataObjects(filters);
218 }
219
220 // Implemented for EmuFrontQueryModel:
221 EmuFrontObject* ExternalExecutableModel::recordToDataObject(const QSqlRecord* rec)
222 {
223     Executable *ex = 0;
224     if (!rec) return ex;
225     int id = rec->value(Executable_Id).toInt();
226     int supid = rec->value(Executable_SetupId).toInt();
227     SetupModel supModel;
228     EmuFrontObject *ob = supModel.getDataObject(supid);
229     Setup *sup = dynamic_cast<Setup*>(ob);
230     QString name = rec->value(Executable_Name).toString();
231     QString exec = rec->value(Executable_Executable).toString();
232     QString opts = rec->value(Executable_Options).toString();
233     int type = rec->value(Executable_TypeId).toInt();
234     ex = new Executable(id, name, exec, opts, sup, type);
235     return ex;
236 }
237
238 QString ExternalExecutableModel::constructFilterById(int id) const
239 {
240     return QString("executable.id=%1").arg(id);
241 }